From 0ad6252f2e4d063cbd4a35b3d2ab299d4e91585f Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 6 Jun 2017 21:02:26 -0700 Subject: [PATCH 01/71] docs(changelog): updated by Nate Fischer [ci skip] --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e0355bf6..f7427c2ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,7 @@ # Change Log -## [Unreleased](https://github.com/shelljs/shelljs/tree/HEAD) - -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.7...HEAD) +## [v0.7.8](https://github.com/shelljs/shelljs/tree/v0.7.8) (2017-06-07) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.7...v0.7.8) **Closed issues:** From 5acb353bc5aaf1ff1e2d633d37a494e162b2a246 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Sun, 27 Nov 2016 13:12:26 -0800 Subject: [PATCH 02/71] Add newline to output of echo (#557) * Add newline to output of echo * Add test --- src/echo.js | 2 +- test/echo.js | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/echo.js b/src/echo.js index 2b0e7d919..045c35eda 100644 --- a/src/echo.js +++ b/src/echo.js @@ -29,6 +29,6 @@ function _echo(opts, messages) { } console.log.apply(console, messages); - return messages.join(' '); + return messages.join(' ') + '\n'; } module.exports = _echo; diff --git a/test/echo.js b/test/echo.js index 7887d88ee..87c48e24f 100644 --- a/test/echo.js +++ b/test/echo.js @@ -5,6 +5,14 @@ import utils from './utils/utils'; shell.config.silent = true; +test.beforeEach(t => { + t.context.tmp = utils.getTempDir(); +}); + +test.afterEach.always(t => { + shell.rm('-rf', t.context.tmp); +}); + // // Valids // @@ -57,3 +65,17 @@ test.cb('-e option', t => { t.end(); }); }); + +test.cb('piping to a file', t => { + // see issue #476 + shell.mkdir(t.context.tmp); + const tmp = `${t.context.tmp}/echo.txt`; + const script = `require('../global.js'); echo('A').toEnd('${tmp}'); echo('B').toEnd('${tmp}');`; + utils.runScript(script, (err, stdout) => { + const result = shell.cat(tmp); + t.falsy(err); + t.is(stdout, 'A\nB\n'); + t.is(result.toString(), 'A\nB\n'); + t.end(); + }); +}); From 5d05d2710836816903ab9103b60172be6004b85d Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Mon, 16 Jan 2017 19:36:46 -0800 Subject: [PATCH 03/71] Safely exit by throwing an error (#649) --- src/common.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/common.js b/src/common.js index 4a1f43456..b5acde1f4 100644 --- a/src/common.js +++ b/src/common.js @@ -410,9 +410,8 @@ function wrap(cmd, fn, options) { /* istanbul ignore next */ if (!state.error) { // If state.error hasn't been set it's an error thrown by Node, not us - probably a bug... - console.error('ShellJS: internal error'); - console.error(e.stack || e); - process.exit(1); + e.name = 'ShellJSInternalError'; + throw e; } if (config.fatal) throw e; } From f74e783890f72399aa7d4d64e248ec0d76b06193 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 17 Jan 2017 16:43:38 -0800 Subject: [PATCH 04/71] chore: remove v0.12 and iojs support (#648) Fixes #647 --- .travis.yml | 5 -- README.md | 2 +- package.json | 3 +- src/common.js | 23 ++------ src/exec.js | 152 +++++++++++++++---------------------------------- src/tempdir.js | 1 - test/exec.js | 11 ++-- 7 files changed, 55 insertions(+), 142 deletions(-) diff --git a/.travis.yml b/.travis.yml index 02eb8bf81..90f780524 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,6 @@ language: c++ sudo: false env: - - NODE_VERSION="0.11" - - NODE_VERSION="0.12" - - NODE_VERSION="iojs-v1" - - NODE_VERSION="iojs-v2" - - NODE_VERSION="iojs-v3" - NODE_VERSION="4" - NODE_VERSION="5" - NODE_VERSION="6" diff --git a/README.md b/README.md index 1f3e6ec0f..a74829108 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ script's dependency on Unix while still keeping its familiar and powerful commands. You can also install it globally so you can run it from outside Node projects - say goodbye to those gnarly Bash scripts! -ShellJS is proudly tested on every node release since `v0.11`! +ShellJS is proudly tested on every node release since `v4`! The project is [unit-tested](http://travis-ci.org/shelljs/shelljs) and battle-tested in projects like: diff --git a/package.json b/package.json index c93e33420..b8ae2a37b 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,6 @@ }, "optionalDependencies": {}, "engines": { - "node": ">=0.11.0", - "iojs": "*" + "node": ">=4" } } diff --git a/src/common.js b/src/common.js index b5acde1f4..f553fd0e9 100644 --- a/src/common.js +++ b/src/common.js @@ -9,22 +9,7 @@ var shell = require('..'); var shellMethods = Object.create(shell); -// objectAssign(target_obj, source_obj1 [, source_obj2 ...]) -// "Ponyfill" for Object.assign -// objectAssign({A:1}, {b:2}, {c:3}) returns {A:1, b:2, c:3} -var objectAssign = typeof Object.assign === 'function' ? - Object.assign : - function objectAssign(target) { - var sources = [].slice.call(arguments, 1); - sources.forEach(function (source) { - Object.keys(source).forEach(function (key) { - target[key] = source[key]; - }); - }); - - return target; - }; -exports.extend = objectAssign; +exports.extend = Object.assign; // Check if we're running under electron var isElectron = Boolean(process.versions.electron); @@ -43,7 +28,7 @@ var DEFAULT_CONFIG = { var config = { reset: function () { - objectAssign(this, DEFAULT_CONFIG); + Object.assign(this, DEFAULT_CONFIG); if (!isElectron) { this.execPath = process.execPath; } @@ -116,7 +101,7 @@ function error(msg, _code, options) { } else if (typeof _code !== 'number') { // only 'msg' options = {}; } - options = objectAssign({}, DEFAULT_OPTIONS, options); + options = Object.assign({}, DEFAULT_OPTIONS, options); if (!state.errorCode) state.errorCode = options.code; @@ -449,7 +434,7 @@ var DEFAULT_WRAP_OPTIONS = { function _register(name, implementation, wrapOptions) { wrapOptions = wrapOptions || {}; // If an option isn't specified, use the default - wrapOptions = objectAssign({}, DEFAULT_WRAP_OPTIONS, wrapOptions); + wrapOptions = Object.assign({}, DEFAULT_WRAP_OPTIONS, wrapOptions); if (shell[name] && !wrapOptions.overWrite) { throw new Error('unable to overwrite `' + name + '` command'); diff --git a/src/exec.js b/src/exec.js index 5d360e868..16066382e 100644 --- a/src/exec.js +++ b/src/exec.js @@ -28,7 +28,6 @@ function execSync(cmd, opts, pipe) { var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); var codeFile = path.resolve(tempDir + '/' + common.randomFileName()); var scriptFile = path.resolve(tempDir + '/' + common.randomFileName()); - var sleepFile = path.resolve(tempDir + '/' + common.randomFileName()); opts = common.extend({ silent: common.config.silent, @@ -37,34 +36,6 @@ function execSync(cmd, opts, pipe) { maxBuffer: DEFAULT_MAXBUFFER_SIZE, }, opts); - var previousStdoutContent = ''; - var previousStderrContent = ''; - // Echoes stdout and stderr changes from running process, if not silent - function updateStream(streamFile) { - if (opts.silent || !fs.existsSync(streamFile)) { - return; - } - - var previousStreamContent; - var procStream; - if (streamFile === stdoutFile) { - previousStreamContent = previousStdoutContent; - procStream = process.stdout; - } else { // assume stderr - previousStreamContent = previousStderrContent; - procStream = process.stderr; - } - - var streamContent = fs.readFileSync(streamFile, 'utf8'); - // No changes since last time? - if (streamContent.length <= previousStreamContent.length) { - return; - } - - procStream.write(streamContent.substr(previousStreamContent.length)); - previousStreamContent = streamContent; - } - if (fs.existsSync(scriptFile)) common.unlinkSync(scriptFile); if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile); if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); @@ -76,86 +47,53 @@ function execSync(cmd, opts, pipe) { opts.cwd = path.resolve(opts.cwd); var optString = JSON.stringify(opts); - if (typeof child.execSync === 'function') { - script = [ - "var child = require('child_process')", - " , fs = require('fs');", - 'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {', - ' var fname = ' + JSON.stringify(codeFile) + ';', - ' if (!err) {', - ' fs.writeFileSync(fname, "0");', - ' } else if (err.code === undefined) {', - ' fs.writeFileSync(fname, "1");', - ' } else {', - ' fs.writeFileSync(fname, err.code.toString());', - ' }', - '});', - 'var stdoutStream = fs.createWriteStream(' + JSON.stringify(stdoutFile) + ');', - 'var stderrStream = fs.createWriteStream(' + JSON.stringify(stderrFile) + ');', - 'childProcess.stdout.pipe(stdoutStream, {end: false});', - 'childProcess.stderr.pipe(stderrStream, {end: false});', - 'childProcess.stdout.pipe(process.stdout);', - 'childProcess.stderr.pipe(process.stderr);', - ].join('\n') + - (pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n') + - [ - 'var stdoutEnded = false, stderrEnded = false;', - 'function tryClosingStdout(){ if(stdoutEnded){ stdoutStream.end(); } }', - 'function tryClosingStderr(){ if(stderrEnded){ stderrStream.end(); } }', - "childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosingStdout(); });", - "childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });", - ].join('\n'); - - fs.writeFileSync(scriptFile, script); - - if (opts.silent) { - opts.stdio = 'ignore'; - } else { - opts.stdio = [0, 1, 2]; - } - - // Welcome to the future - try { - child.execSync(execCommand, opts); - } catch (e) { - // Clean up immediately if we have an exception - try { common.unlinkSync(scriptFile); } catch (e2) {} - try { common.unlinkSync(stdoutFile); } catch (e2) {} - try { common.unlinkSync(stderrFile); } catch (e2) {} - try { common.unlinkSync(codeFile); } catch (e2) {} - throw e; - } + script = [ + "var child = require('child_process')", + " , fs = require('fs');", + 'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {', + ' var fname = ' + JSON.stringify(codeFile) + ';', + ' if (!err) {', + ' fs.writeFileSync(fname, "0");', + ' } else if (err.code === undefined) {', + ' fs.writeFileSync(fname, "1");', + ' } else {', + ' fs.writeFileSync(fname, err.code.toString());', + ' }', + '});', + 'var stdoutStream = fs.createWriteStream(' + JSON.stringify(stdoutFile) + ');', + 'var stderrStream = fs.createWriteStream(' + JSON.stringify(stderrFile) + ');', + 'childProcess.stdout.pipe(stdoutStream, {end: false});', + 'childProcess.stderr.pipe(stderrStream, {end: false});', + 'childProcess.stdout.pipe(process.stdout);', + 'childProcess.stderr.pipe(process.stderr);', + ].join('\n') + + (pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n') + + [ + 'var stdoutEnded = false, stderrEnded = false;', + 'function tryClosingStdout(){ if(stdoutEnded){ stdoutStream.end(); } }', + 'function tryClosingStderr(){ if(stderrEnded){ stderrStream.end(); } }', + "childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosingStdout(); });", + "childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });", + ].join('\n'); + + fs.writeFileSync(scriptFile, script); + + if (opts.silent) { + opts.stdio = 'ignore'; } else { - cmd += ' > ' + stdoutFile + ' 2> ' + stderrFile; // works on both win/unix - - script = [ - "var child = require('child_process')", - " , fs = require('fs');", - 'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {', - ' var fname = ' + JSON.stringify(codeFile) + ';', - ' if (!err) {', - ' fs.writeFileSync(fname, "0");', - ' } else if (err.code === undefined) {', - ' fs.writeFileSync(fname, "1");', - ' } else {', - ' fs.writeFileSync(fname, err.code.toString());', - ' }', - '});', - ].join('\n') + - (pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n'); - - fs.writeFileSync(scriptFile, script); - - child.exec(execCommand, opts); + opts.stdio = [0, 1, 2]; + } - // The wait loop - // sleepFile is used as a dummy I/O op to mitigate unnecessary CPU usage - // (tried many I/O sync ops, writeFileSync() seems to be only one that is effective in reducing - // CPU usage, though apparently not so much on Windows) - while (!fs.existsSync(codeFile)) { updateStream(stdoutFile); fs.writeFileSync(sleepFile, 'a'); } - while (!fs.existsSync(stdoutFile)) { updateStream(stdoutFile); fs.writeFileSync(sleepFile, 'a'); } - while (!fs.existsSync(stderrFile)) { updateStream(stderrFile); fs.writeFileSync(sleepFile, 'a'); } - try { common.unlinkSync(sleepFile); } catch (e) {} + // Welcome to the future + try { + child.execSync(execCommand, opts); + } catch (e) { + // Clean up immediately if we have an exception + try { common.unlinkSync(scriptFile); } catch (e2) {} + try { common.unlinkSync(stdoutFile); } catch (e2) {} + try { common.unlinkSync(stderrFile); } catch (e2) {} + try { common.unlinkSync(codeFile); } catch (e2) {} + throw e; } // At this point codeFile exists, but it's not necessarily flushed yet. diff --git a/src/tempdir.js b/src/tempdir.js index a2d15be36..b3a6cca38 100644 --- a/src/tempdir.js +++ b/src/tempdir.js @@ -41,7 +41,6 @@ function _tempDir() { if (state.tempDir) return state.tempDir; // from cache state.tempDir = writeableDir(os.tmpdir && os.tmpdir()) || // node 0.10+ - writeableDir(os.tmpDir && os.tmpDir()) || // node 0.8+ writeableDir(process.env.TMPDIR) || writeableDir(process.env.TEMP) || writeableDir(process.env.TMP) || diff --git a/test/exec.js b/test/exec.js index 7110e34f9..6a7b44377 100644 --- a/test/exec.js +++ b/test/exec.js @@ -112,10 +112,8 @@ test('set maxBuffer (very small)', t => { t.falsy(shell.error()); t.is(result.code, 0); t.is(result.stdout, '1234567890' + os.EOL); - if (process.version >= 'v0.11') { // this option doesn't work on v0.10 - shell.exec('echo 1234567890', { maxBuffer: 6 }); - t.truthy(shell.error()); - } + shell.exec('echo 1234567890', { maxBuffer: 6 }); + t.truthy(shell.error()); }); test('set timeout option', t => { @@ -125,9 +123,8 @@ test('set timeout option', t => { if (process.version >= 'v0.11') { // this option doesn't work on v0.10 shell.exec(`${JSON.stringify(shell.config.execPath)} resources/exec/slow.js 100`, { timeout: 10 }); // times out - - t.truthy(shell.error()); } + t.truthy(shell.error()); }); test('check process.env works', t => { @@ -148,7 +145,7 @@ test('set shell option (TODO: add tests for Windows)', t => { t.is(result.stdout, '/bin/sh\n'); // sh by default const bashPath = shell.which('bash').trim(); // this option doesn't work on v0.10 - if (bashPath && process.version >= 'v0.11') { + if (bashPath) { result = shell.exec('echo $0', { shell: '/bin/bash' }); t.falsy(shell.error()); t.is(result.code, 0); From 97a8c1969a757bd0b3ed0b4f212eef9d8ad5e1f8 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Thu, 16 Mar 2017 01:08:48 -0700 Subject: [PATCH 05/71] fix(grep, sed, sort, uniq): Split only on newline characters (#690) * Split on newlines only * Only split lines if need be * Clarify code by making use of Array.prototype.reduce --- src/grep.js | 2 +- src/sed.js | 2 +- src/sort.js | 14 ++++++-------- src/uniq.js | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/grep.js b/src/grep.js index 30842bcb8..8cf53b157 100644 --- a/src/grep.js +++ b/src/grep.js @@ -47,12 +47,12 @@ function _grep(options, regex, files) { } var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); - var lines = contents.split(/\r*\n/); if (options.nameOnly) { if (contents.match(regex)) { grep.push(file); } } else { + var lines = contents.split('\n'); lines.forEach(function (line) { var matched = line.match(regex); if ((options.inverse && !matched) || (!options.inverse && matched)) { diff --git a/src/sed.js b/src/sed.js index dfdc0a747..7d396e7e9 100644 --- a/src/sed.js +++ b/src/sed.js @@ -69,7 +69,7 @@ function _sed(options, regex, replacement, files) { } var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); - var lines = contents.split(/\r*\n/); + var lines = contents.split('\n'); var result = lines.map(function (line) { return line.replace(regex, replacement); }).join('\n'); diff --git a/src/sort.js b/src/sort.js index 2ebccd7f4..5dd8d75fc 100644 --- a/src/sort.js +++ b/src/sort.js @@ -67,26 +67,24 @@ function _sort(options, files) { files.unshift('-'); } - var lines = []; - files.forEach(function (file) { + var lines = files.reduce(function (accum, file) { if (file !== '-') { if (!fs.existsSync(file)) { common.error('no such file or directory: ' + file, { continue: true }); - return; + return accum; } else if (fs.statSync(file).isDirectory()) { common.error('read failed: ' + file + ': Is a directory', { continue: true, }); - return; + return accum; } } var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); - lines = lines.concat(contents.trimRight().split(/\r*\n/)); - }); + return accum.concat(contents.trimRight().split('\n')); + }, []); - var sorted; - sorted = lines.sort(options.numerical ? numericalCmp : unixCmp); + var sorted = lines.sort(options.numerical ? numericalCmp : unixCmp); if (options.reverse) { sorted = sorted.reverse(); diff --git a/src/uniq.js b/src/uniq.js index 30121616a..8c0f04010 100644 --- a/src/uniq.js +++ b/src/uniq.js @@ -55,7 +55,7 @@ function _uniq(options, input, output) { var lines = (input ? fs.readFileSync(input, 'utf8') : pipe). trimRight(). - split(/\r*\n/); + split('\n'); var compare = function (a, b) { return options.ignoreCase ? From 18034486a51a206b4dfcef14f504528a98b67207 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 16 Mar 2017 10:10:53 -0700 Subject: [PATCH 06/71] Echo stdout (#677) * Add newline to output of echo (#557) * Add newline to output of echo * Add test * Throw an error if the options string does not start with '-' (#615) * Throw an error if the options string does not start with '-' * Add test * Change message grammar * Add -n option to echo * Fix null argument issue * Add -n tests * Add documentation * Add -en escaped character test * Add function to parse options for echo * Use parseOptions to parse echo options * Simplify control flow * parseOptions throws now * Allow null to be echoed * Prevent echo stderr on unrecognized option * Add test to check stderr of returned value * Use consistent variable name * Change test message, leave TODO about console output --- README.md | 2 ++ src/common.js | 2 ++ src/echo.js | 42 ++++++++++++++++++++++++++++++------- test/common.js | 6 ++++++ test/echo.js | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a74829108..b59c8c821 100644 --- a/README.md +++ b/README.md @@ -259,12 +259,14 @@ See also: pushd, popd Available options: + `-e`: interpret backslash escapes (default) ++ `-n`: remove trailing newline from output Examples: ```javascript echo('hello world'); var str = echo('hello world'); +echo('-n', 'no newline at end'); ``` Prints string to stdout, and returns string with additional utility methods diff --git a/src/common.js b/src/common.js index f553fd0e9..2b48ae030 100644 --- a/src/common.js +++ b/src/common.js @@ -172,6 +172,8 @@ exports.getUserHome = getUserHome; // parseOptions('-a', {'a':'alice', 'b':'bob'}); // Returns {'reference': 'string-value', 'bob': false} when passed two dictionaries of the form: // parseOptions({'-r': 'string-value'}, {'r':'reference', 'b':'bob'}); +// Throws an error when passed a string that does not start with '-': +// parseOptions('a', {'a':'alice'}); // throws function parseOptions(opt, map, errorOptions) { // Validate input if (typeof opt !== 'string' && !isObject(opt)) { diff --git a/src/echo.js b/src/echo.js index 045c35eda..13cce3999 100644 --- a/src/echo.js +++ b/src/echo.js @@ -1,3 +1,5 @@ +var format = require('util').format; + var common = require('./common'); common.register('echo', _echo, { @@ -9,26 +11,52 @@ common.register('echo', _echo, { //@ Available options: //@ //@ + `-e`: interpret backslash escapes (default) +//@ + `-n`: remove trailing newline from output //@ //@ Examples: //@ //@ ```javascript //@ echo('hello world'); //@ var str = echo('hello world'); +//@ echo('-n', 'no newline at end'); //@ ``` //@ //@ Prints string to stdout, and returns string with additional utility methods //@ like `.to()`. -function _echo(opts, messages) { +function _echo(opts) { // allow strings starting with '-', see issue #20 - messages = [].slice.call(arguments, opts ? 0 : 1); + var messages = [].slice.call(arguments, opts ? 0 : 1); + var options = {}; + + // If the first argument starts with '-', parse it as options string. + // If parseOptions throws, it wasn't an options string. + try { + options = common.parseOptions(messages[0], { + 'e': 'escapes', + 'n': 'no_newline' + }, { + silent: true + }); - if (messages[0] === '-e') { - // ignore -e - messages.shift(); + // Allow null to be echoed + if (messages[0]) { + messages.shift(); + } + } catch (_) { + // Clear out error if an error occurred + common.state.error = null; } - console.log.apply(console, messages); - return messages.join(' ') + '\n'; + var output = format.apply(null, messages); + + // Add newline if -n is not passed. + if (!options.no_newline) { + output += '\n'; + } + + process.stdout.write(output); + + return output; } + module.exports = _echo; diff --git a/test/common.js b/test/common.js index a6f1e9f52..2f5450790 100644 --- a/test/common.js +++ b/test/common.js @@ -269,6 +269,12 @@ test('common.parseOptions using an object to hold options', t => { t.false(result.reverse); }); +test('common.parseOptions throws when passed a string not starting with "-"', t => { + t.throws(() => { + common.parseOptions('a', { '-a': 'throws' }); + }, 'Options string must start with "-"'); +}); + test('Some basic tests on the ShellString type', t => { const result = shell.ShellString('foo'); t.is(result.toString(), 'foo'); diff --git a/test/echo.js b/test/echo.js index 87c48e24f..97d031ca6 100644 --- a/test/echo.js +++ b/test/echo.js @@ -79,3 +79,60 @@ test.cb('piping to a file', t => { t.end(); }); }); + +test.cb('-n option', t => { + const script = "require('../global.js'); echo('-n', 'message');"; + utils.runScript(script, (err, stdout) => { + t.falsy(err); + t.is(stdout, 'message'); + t.end(); + }); +}); + +test.cb('-ne option', t => { + const script = "require('../global.js'); echo('-ne', 'message');"; + utils.runScript(script, (err, stdout) => { + t.falsy(err); + t.is(stdout, 'message'); + t.end(); + }); +}); + +test.cb('-en option', t => { + const script = "require('../global.js'); echo('-en', 'message');"; + utils.runScript(script, (err, stdout) => { + t.falsy(err); + t.is(stdout, 'message'); + t.end(); + }); +}); + +test.cb('-en option with escaped characters', t => { + const script = "require('../global.js'); echo('-en', '\\tmessage\\n');"; + utils.runScript(script, (err, stdout) => { + t.falsy(err); + t.is(stdout, '\tmessage\n'); + t.end(); + }); +}); + +test.cb('piping to a file with -n', t => { + // see issue #476 + shell.mkdir(t.context.tmp); + const tmp = `${t.context.tmp}/echo.txt`; + const script = `require('../global.js'); echo('-n', 'A').toEnd('${tmp}'); echo('-n', 'B').toEnd('${tmp}');`; + utils.runScript(script, (err, stdout) => { + const result = shell.cat(tmp); + t.falsy(err); + t.is(stdout, 'AB'); + t.is(result.toString(), 'AB'); + t.end(); + }); +}); + +test('stderr with unrecognized options is empty', t => { + // TODO: console output here needs to be muted + const result = shell.echo('-asdf'); + t.falsy(result.stderr); + t.is(result.stdout, '-asdf\n'); +}); From c1d8fecc565b51788baa714450f6c7cb03851517 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sun, 9 Apr 2017 19:31:47 -0700 Subject: [PATCH 07/71] Fix broken test --- src/common.js | 2 +- test/common.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common.js b/src/common.js index 2b48ae030..40b0600f0 100644 --- a/src/common.js +++ b/src/common.js @@ -197,7 +197,7 @@ function parseOptions(opt, map, errorOptions) { if (typeof opt === 'string') { if (opt[0] !== '-') { - error("Options string must start with a '-'", errorOptions || {}); + throw new Error("Options string must start with a '-'"); } // e.g. chars = ['R', 'f'] diff --git a/test/common.js b/test/common.js index 2f5450790..b59f7a267 100644 --- a/test/common.js +++ b/test/common.js @@ -272,7 +272,7 @@ test('common.parseOptions using an object to hold options', t => { test('common.parseOptions throws when passed a string not starting with "-"', t => { t.throws(() => { common.parseOptions('a', { '-a': 'throws' }); - }, 'Options string must start with "-"'); + }, Error, "Options string must start with a '-'"); }); test('Some basic tests on the ShellString type', t => { From e8ec60bc2fb54d024403b916f0b2b093661cffa5 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Fri, 5 May 2017 19:12:21 -0700 Subject: [PATCH 08/71] Echo test mocks (#708) * Add stdout/stderr test mocks * Mock stdout/stderr during echo tests * Fix lint issues * Use 'use strict' * Re-implement mocks as a prototype * Implement mocks as a single-instance * Remove redundant test * Create mocked stdout/stderr.write methods once --- src/echo.js | 4 +- test/echo.js | 189 +++++++++++++++++++++++--------------------- test/utils/mocks.js | 44 +++++++++++ 3 files changed, 147 insertions(+), 90 deletions(-) create mode 100644 test/utils/mocks.js diff --git a/src/echo.js b/src/echo.js index 13cce3999..7229ce7f2 100644 --- a/src/echo.js +++ b/src/echo.js @@ -33,9 +33,9 @@ function _echo(opts) { try { options = common.parseOptions(messages[0], { 'e': 'escapes', - 'n': 'no_newline' + 'n': 'no_newline', }, { - silent: true + silent: true, }); // Allow null to be echoed diff --git a/test/echo.js b/test/echo.js index 97d031ca6..f8afbee26 100644 --- a/test/echo.js +++ b/test/echo.js @@ -2,137 +2,150 @@ import test from 'ava'; import shell from '..'; import utils from './utils/utils'; +import mocks from './utils/mocks'; shell.config.silent = true; test.beforeEach(t => { t.context.tmp = utils.getTempDir(); + mocks.init(); }); test.afterEach.always(t => { shell.rm('-rf', t.context.tmp); + mocks.restore(); }); // // Valids // -test.cb('simple test with defaults', t => { - const script = 'require(\'../global.js\'); echo("hello", "world");'; - utils.runScript(script, (err, stdout, stderr) => { - t.falsy(err); - t.is(stdout, 'hello world\n'); - t.is(stderr, ''); - t.end(); - }); +test('simple test with defaults', t => { + const result = shell.echo('hello', 'world'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(stdout, 'hello world\n'); + t.is(stderr, ''); }); -test.cb('allow arguments to begin with a hyphen', t => { +test('allow arguments to begin with a hyphen', t => { // see issue #20 - const script = 'require(\'../global.js\'); echo("-asdf", "111");'; - utils.runScript(script, (err, stdout, stderr) => { - t.falsy(err); - t.is(stdout, '-asdf 111\n'); - t.is(stderr, ''); - t.end(); - }); + const result = shell.echo('-asdf', '111'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(result.code, 1); + t.is(stdout, '-asdf 111\n'); + t.is(stderr, ''); }); -test.cb("using null as an explicit argument doesn't crash the function", t => { - const script = 'require(\'../global.js\'); echo(null);'; - utils.runScript(script, (err, stdout, stderr) => { - t.falsy(err); - t.is(stdout, 'null\n'); - t.is(stderr, ''); - t.end(); - }); +test("using null as an explicit argument doesn't crash the function", t => { + const result = shell.echo(null); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(stdout, 'null\n'); + t.is(stderr, ''); }); -test.cb('simple test with silent(true)', t => { - const script = 'require(\'../global.js\'); config.silent=true; echo(555);'; - utils.runScript(script, (err, stdout) => { - t.falsy(err); - t.is(stdout, '555\n'); - t.end(); - }); +test('-e option', t => { + const result = shell.echo('-e', '\tmessage'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(stdout, '\tmessage\n'); + t.is(stderr, ''); }); -test.cb('-e option', t => { - const script = "require('../global.js'); echo('-e', '\\tmessage');"; - utils.runScript(script, (err, stdout) => { - t.falsy(err); - t.is(stdout, '\tmessage\n'); - t.end(); - }); -}); - -test.cb('piping to a file', t => { +test('piping to a file', t => { // see issue #476 shell.mkdir(t.context.tmp); const tmp = `${t.context.tmp}/echo.txt`; - const script = `require('../global.js'); echo('A').toEnd('${tmp}'); echo('B').toEnd('${tmp}');`; - utils.runScript(script, (err, stdout) => { - const result = shell.cat(tmp); - t.falsy(err); - t.is(stdout, 'A\nB\n'); - t.is(result.toString(), 'A\nB\n'); - t.end(); - }); + const resultA = shell.echo('A').toEnd(tmp); + t.falsy(shell.error()); + t.is(resultA.code, 0); + const resultB = shell.echo('B').toEnd(tmp); + t.falsy(shell.error()); + t.is(resultB.code, 0); + const result = shell.cat(tmp); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(stdout, 'A\nB\n'); + t.is(stderr, ''); + t.is(result.toString(), 'A\nB\n'); }); -test.cb('-n option', t => { - const script = "require('../global.js'); echo('-n', 'message');"; - utils.runScript(script, (err, stdout) => { - t.falsy(err); - t.is(stdout, 'message'); - t.end(); - }); +test('-n option', t => { + const result = shell.echo('-n', 'message'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(stdout, 'message'); + t.is(stderr, ''); }); -test.cb('-ne option', t => { - const script = "require('../global.js'); echo('-ne', 'message');"; - utils.runScript(script, (err, stdout) => { - t.falsy(err); - t.is(stdout, 'message'); - t.end(); - }); +test('-ne option', t => { + const result = shell.echo('-ne', 'message'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(stdout, 'message'); + t.is(stderr, ''); }); -test.cb('-en option', t => { - const script = "require('../global.js'); echo('-en', 'message');"; - utils.runScript(script, (err, stdout) => { - t.falsy(err); - t.is(stdout, 'message'); - t.end(); - }); +test('-en option', t => { + const result = shell.echo('-en', 'message'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(stdout, 'message'); + t.is(stderr, ''); }); -test.cb('-en option with escaped characters', t => { - const script = "require('../global.js'); echo('-en', '\\tmessage\\n');"; - utils.runScript(script, (err, stdout) => { - t.falsy(err); - t.is(stdout, '\tmessage\n'); - t.end(); - }); +test('-en option with escaped characters', t => { + const result = shell.echo('-en', '\tmessage\n'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(stdout, '\tmessage\n'); + t.is(stderr, ''); }); -test.cb('piping to a file with -n', t => { +test('piping to a file with -n', t => { // see issue #476 shell.mkdir(t.context.tmp); const tmp = `${t.context.tmp}/echo.txt`; - const script = `require('../global.js'); echo('-n', 'A').toEnd('${tmp}'); echo('-n', 'B').toEnd('${tmp}');`; - utils.runScript(script, (err, stdout) => { - const result = shell.cat(tmp); - t.falsy(err); - t.is(stdout, 'AB'); - t.is(result.toString(), 'AB'); - t.end(); - }); + const resultA = shell.echo('-n', 'A').toEnd(tmp); + t.falsy(shell.error()); + t.is(resultA.code, 0); + const resultB = shell.echo('-n', 'B').toEnd(tmp); + t.falsy(shell.error()); + t.is(resultB.code, 0); + const result = shell.cat(tmp); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(stdout, 'AB'); + t.is(stderr, ''); + t.is(result.toString(), 'AB'); }); test('stderr with unrecognized options is empty', t => { - // TODO: console output here needs to be muted const result = shell.echo('-asdf'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(result.code, 1); t.falsy(result.stderr); - t.is(result.stdout, '-asdf\n'); + t.is(stdout, '-asdf\n'); + t.is(stderr, ''); }); diff --git a/test/utils/mocks.js b/test/utils/mocks.js new file mode 100644 index 000000000..79dc55087 --- /dev/null +++ b/test/utils/mocks.js @@ -0,0 +1,44 @@ +function addToString(str, val) { + if (Buffer.isBuffer(val)) { + return str + val.toString(); + } + return str + val; +} + +function joinData(data) { + return data.reduce(addToString, ''); +} + +function wrapWrite(target) { + return function write(val) { + target.push(val); + return true; + }; +} + +const _processStdoutWrite = process.stdout.write; +const _processStderrWrite = process.stderr.write; +const _stdout = []; +const _stderr = []; +const _stdoutWrite = wrapWrite(_stdout); +const _stderrWrite = wrapWrite(_stderr); + +exports.stdout = function stdout() { + return joinData(_stdout); +}; + +exports.stderr = function stderr() { + return joinData(_stderr); +}; + +exports.init = function init() { + process.stdout.write = _stdoutWrite; + process.stderr.write = _stderrWrite; +}; + +exports.restore = function restore() { + process.stdout.write = _processStdoutWrite; + process.stderr.write = _processStderrWrite; + _stdout.splice(0); + _stderr.splice(0); +}; From 522a46dcf4c2846829826b7e546a10d806bce3bd Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Wed, 31 May 2017 16:03:13 -0700 Subject: [PATCH 09/71] Deprecate common.getUserHome, advise using os.homedir instead (#725) * Deprecate common.getUserHome, advise using os.homedir instead * Remove common.getUserHome --- src/cd.js | 3 ++- src/common.js | 15 +-------------- test/cd.js | 10 +++++----- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/cd.js b/src/cd.js index 634ed835c..c6f1ada33 100644 --- a/src/cd.js +++ b/src/cd.js @@ -1,4 +1,5 @@ var fs = require('fs'); +var os = require('os'); var common = require('./common'); common.register('cd', _cd, {}); @@ -8,7 +9,7 @@ common.register('cd', _cd, {}); //@ Changes to directory `dir` for the duration of the script. Changes to home //@ directory if no argument is supplied. function _cd(options, dir) { - if (!dir) dir = common.getUserHome(); + if (!dir) dir = os.homedir(); if (dir === '-') { if (!process.env.OLDPWD) { diff --git a/src/common.js b/src/common.js index 40b0600f0..13753a12f 100644 --- a/src/common.js +++ b/src/common.js @@ -155,19 +155,6 @@ function ShellString(stdout, stderr, code) { exports.ShellString = ShellString; -// Return the home directory in a platform-agnostic way, with consideration for -// older versions of node -function getUserHome() { - var result; - if (os.homedir) { - result = os.homedir(); // node 3+ - } else { - result = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']; - } - return result; -} -exports.getUserHome = getUserHome; - // Returns {'alice': true, 'bob': false} when passed a string and dictionary as follows: // parseOptions('-a', {'a':'alice', 'b':'bob'}); // Returns {'reference': 'string-value', 'bob': false} when passed two dictionaries of the form: @@ -363,7 +350,7 @@ function wrap(cmd, fn, options) { }); // Expand the '~' if appropriate - var homeDir = getUserHome(); + var homeDir = os.homedir(); args = args.map(function (arg) { if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') { return arg.replace(/^~/, homeDir); diff --git a/test/cd.js b/test/cd.js index ca9e88910..3c15b1a3d 100644 --- a/test/cd.js +++ b/test/cd.js @@ -1,10 +1,10 @@ import fs from 'fs'; +import os from 'os'; import path from 'path'; import test from 'ava'; import shell from '..'; -import common from '../src/common'; import utils from './utils/utils'; const cur = shell.pwd().toString(); @@ -90,16 +90,16 @@ test('cd + other commands', t => { test('Tilde expansion', t => { shell.cd('~'); - t.is(process.cwd(), common.getUserHome()); + t.is(process.cwd(), os.homedir()); shell.cd('..'); - t.not(process.cwd(), common.getUserHome()); + t.not(process.cwd(), os.homedir()); shell.cd('~'); // Change back to home - t.is(process.cwd(), common.getUserHome()); + t.is(process.cwd(), os.homedir()); }); test('Goes to home directory if no arguments are passed', t => { const result = shell.cd(); t.falsy(shell.error()); t.is(result.code, 0); - t.is(process.cwd(), common.getUserHome()); + t.is(process.cwd(), os.homedir()); }); From c16fb7dac9dfec6cec29cfe633daece83a127d47 Mon Sep 17 00:00:00 2001 From: Vojtech Jasny Date: Sat, 17 Jun 2017 00:55:25 +0200 Subject: [PATCH 10/71] Remove PDF.js mention from README.md (#738) Fixes #737. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index b59c8c821..51082f47c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ ShellJS is proudly tested on every node release since `v4`! The project is [unit-tested](http://travis-ci.org/shelljs/shelljs) and battle-tested in projects like: -+ [PDF.js](http://github.com/mozilla/pdf.js) - Firefox's next-gen PDF reader + [Firebug](http://getfirebug.com/) - Firefox's infamous debugger + [JSHint](http://jshint.com) & [ESLint](http://eslint.org/) - popular JavaScript linters + [Zepto](http://zeptojs.com) - jQuery-compatible JavaScript library for modern browsers From 291241811f27963a663350d5aefa5a76b2a9d719 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 17 Jun 2017 18:31:24 -0700 Subject: [PATCH 11/71] test(head): improve coverage (#743) This adds a test for `head()` on the right-hand side of a pipe. This also removes the try-catch surrounding `fs.openSync()`, because it was unreachable code. `fs.existsSync()` guarantees that the file exists, and `fs.openSync()` only throws if the file does not exist, according to official documentation. Fixes #671 --- src/head.js | 11 +++-------- test/head.js | 7 +++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/head.js b/src/head.js index e112e49e1..2640b13b4 100644 --- a/src/head.js +++ b/src/head.js @@ -8,20 +8,14 @@ common.register('head', _head, { }, }); -// This reads n or more lines, or the entire file, whichever is less. +// Reads |numLines| lines or the entire file, whichever is less. function readSomeLines(file, numLines) { var buf = common.buffer(); var bufLength = buf.length; var bytesRead = bufLength; var pos = 0; - var fdr = null; - - try { - fdr = fs.openSync(file, 'r'); - } catch (e) { - common.error('cannot read file: ' + file); - } + var fdr = fs.openSync(file, 'r'); var numLinesRead = 0; var ret = ''; while (bytesRead === bufLength && numLinesRead < numLines) { @@ -35,6 +29,7 @@ function readSomeLines(file, numLines) { fs.closeSync(fdr); return ret; } + //@ //@ ### head([{'-n': \},] file [, file ...]) //@ ### head([{'-n': \},] file_array) diff --git a/test/head.js b/test/head.js index 5d3beb3b2..0f976e543 100644 --- a/test/head.js +++ b/test/head.js @@ -127,3 +127,10 @@ test('negative values (-num) are the same as (numLines - num)', t => { t.is(result.code, 0); t.is(result.toString(), 'file1 1\nfile1 2\nfile1 3\nfile1 4\n'); }); + +test('right-hand side of a pipe', t => { + const result = shell.cat('resources/head/file1.txt').head(); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(result.toString(), topOfFile1.slice(0, 10).join('\n') + '\n'); +}); From 5823ab18bbbf6f020b294a69027b7b0adc7528da Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 17 Jun 2017 19:09:01 -0700 Subject: [PATCH 12/71] test(exec): add tests for coverage (#744) * test(exec): add tests for coverage No logic change. This adds one test to cover some missing lines, and adds some `istanbul ignore` directives. I see 100% line coverage for `src/exec.js` when running: ```sh $ nyc --reporter=text --reporter=lcov ava --serial test/exec.js` ``` Fixes #742 * Fix lint --- src/exec.js | 2 ++ test/exec.js | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/exec.js b/src/exec.js index 16066382e..6a2e1261a 100644 --- a/src/exec.js +++ b/src/exec.js @@ -78,6 +78,7 @@ function execSync(cmd, opts, pipe) { fs.writeFileSync(scriptFile, script); + /* istanbul ignore else */ if (opts.silent) { opts.stdio = 'ignore'; } else { @@ -137,6 +138,7 @@ function execAsync(cmd, opts, pipe, callback) { callback(0, stdout, stderr); } else if (err.code === undefined) { // See issue #536 + /* istanbul ignore next */ callback(1, stdout, stderr); } else { callback(err.code, stdout, stderr); diff --git a/test/exec.js b/test/exec.js index 6a7b44377..f22c73120 100644 --- a/test/exec.js +++ b/test/exec.js @@ -199,3 +199,12 @@ test.cb('callback as 3rd argument (silent:true)', t => { t.end(); }); }); + +test.cb('command that fails', t => { + shell.exec('shx cp onlyOneCpArgument.txt', { silent: true }, (code, stdout, stderr) => { + t.is(code, 1); + t.is(stdout, ''); + t.is(stderr, 'cp: missing and/or \n'); + t.end(); + }); +}); From 38b57c8942e68a8bff35fb9177a856dd6f62222a Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sun, 18 Jun 2017 11:51:01 -0700 Subject: [PATCH 13/71] chore: add skipOnWin and skipOnUnix test helpers (#746) This adds `skipOnWin` and `skipOnUnix` to help us manage our platform-dependent tests. These methods give a nice warning message when we skip tests. We may also consider adding warnings when running platform-dependent tests. Part of the motivation for this is if we ever update to AVA v0.19. This version requires at least one assertion per test case. While this could be disabled with an AVA setting, we instead benefit from warnings for any case when we unintentionally skip assertions. This adds chalk as a dev dependency to enable colored messages. --- package.json | 1 + test/chmod.js | 56 ++++++++++++++++++++++----------------------- test/cp.js | 32 +++++++++++++------------- test/exec.js | 5 ++-- test/ls.js | 24 +++++++++---------- test/mkdir.js | 4 ++-- test/rm.js | 12 +++++----- test/test.js | 21 +++++++++-------- test/touch.js | 4 ++-- test/utils/utils.js | 24 ++++++++++++++++++- test/which.js | 5 ++-- 11 files changed, 107 insertions(+), 81 deletions(-) diff --git a/package.json b/package.json index b8ae2a37b..eab128b74 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ }, "devDependencies": { "ava": "^0.16.0", + "chalk": "^1.1.3", "codecov": "^1.0.1", "coffee-script": "^1.10.0", "eslint": "^2.0.0", diff --git a/test/chmod.js b/test/chmod.js index 3ed210e5b..60e09ff14 100644 --- a/test/chmod.js +++ b/test/chmod.js @@ -32,7 +32,7 @@ test('invalid permissions', t => { }); test('Basic usage with octal codes', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('755', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( @@ -45,11 +45,11 @@ test('Basic usage with octal codes', t => { fs.statSync(`${TMP}/chmod/file1`).mode & BITMASK, parseInt('644', 8) ); - } + }); }); test('symbolic mode', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('o+x', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( @@ -58,11 +58,11 @@ test('symbolic mode', t => { ); result = shell.chmod('644', `${TMP}/chmod/file1`); t.is(result.code, 0); - } + }); }); test('symbolic mode, without group', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('+x', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( @@ -71,11 +71,11 @@ test('symbolic mode, without group', t => { ); result = shell.chmod('644', `${TMP}/chmod/file1`); t.is(result.code, 0); - } + }); }); test('Test setuid', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('u+s', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( @@ -102,11 +102,11 @@ test('Test setuid', t => { ); result = shell.chmod('u-s', `${TMP}/chmod/c`); t.is(result.code, 0); - } + }); }); test('Test setgid', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('g+s', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( @@ -119,11 +119,11 @@ test('Test setgid', t => { fs.statSync(`${TMP}/chmod/file1`).mode & BITMASK, parseInt('644', 8) ); - } + }); }); test('Test sticky bit', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('+t', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( @@ -137,11 +137,11 @@ test('Test sticky bit', t => { parseInt('644', 8) ); t.is(fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('1000', 8), 0); - } + }); }); test('Test directories', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('a-w', `${TMP}/chmod/b/a/b`); t.is(result.code, 0); t.is( @@ -150,11 +150,11 @@ test('Test directories', t => { ); result = shell.chmod('755', `${TMP}/chmod/b/a/b`); t.is(result.code, 0); - } + }); }); test('Test recursion', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('-R', 'a+w', `${TMP}/chmod/b`); t.is(result.code, 0); t.is( @@ -167,11 +167,11 @@ test('Test recursion', t => { fs.statSync(`${TMP}/chmod/b/a/b`).mode & BITMASK, parseInt('755', 8) ); - } + }); }); test('Test symbolic links w/ recursion - WARNING: *nix only', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { fs.symlinkSync(`${TMP}/chmod/b/a`, `${TMP}/chmod/a/b/c/link`, 'dir'); let result = shell.chmod('-R', 'u-w', `${TMP}/chmod/a/b`); t.is(result.code, 0); @@ -186,7 +186,7 @@ test('Test symbolic links w/ recursion - WARNING: *nix only', t => { result = shell.chmod('-R', 'u+w', `${TMP}/chmod/a/b`); t.is(result.code, 0); fs.unlinkSync(`${TMP}/chmod/a/b/c/link`); - } + }); }); test('Test combinations', t => { @@ -223,7 +223,7 @@ test('multiple symbolic modes #2', t => { }); test('multiple symbolic modes #3', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('a-rwx,u+rwx', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( @@ -232,7 +232,7 @@ test('multiple symbolic modes #3', t => { ); result = shell.chmod('644', `${TMP}/chmod/file1`); t.is(result.code, 0); - } + }); }); test('u+rw', t => { @@ -249,7 +249,7 @@ test('u+rw', t => { }); test('u+wx', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('000', `${TMP}/chmod/file1`); t.is(result.code, 0); result = shell.chmod('u+wx', `${TMP}/chmod/file1`); @@ -260,11 +260,11 @@ test('u+wx', t => { ); result = shell.chmod('644', `${TMP}/chmod/file1`); t.is(result.code, 0); - } + }); }); test('Multiple symbolic modes at once', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('000', `${TMP}/chmod/file1`); t.is(result.code, 0); result = shell.chmod('u+r,g+w,o+x', `${TMP}/chmod/file1`); @@ -275,11 +275,11 @@ test('Multiple symbolic modes at once', t => { ); result = shell.chmod('644', `${TMP}/chmod/file1`); t.is(result.code, 0); - } + }); }); test('u+rw,g+wx', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.chmod('000', `${TMP}/chmod/file1`); t.is(result.code, 0); result = shell.chmod('u+rw,g+wx', `${TMP}/chmod/file1`); @@ -290,7 +290,7 @@ test('u+rw,g+wx', t => { ); result = shell.chmod('644', `${TMP}/chmod/file1`); t.is(result.code, 0); - } + }); }); test('u-x,g+rw', t => { @@ -337,7 +337,7 @@ test('Numeric modes', t => { }); test('Make sure chmod succeeds for a variety of octal codes', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { t.is( fs.statSync(`${TMP}/chmod/xdir`).mode & parseInt('755', 8), parseInt('755', 8) @@ -354,5 +354,5 @@ test('Make sure chmod succeeds for a variety of octal codes', t => { fs.statSync(`${TMP}/chmod/xdir/deep/file`).mode & parseInt('644', 8), parseInt('644', 8) ); - } + }); }); diff --git a/test/cp.js b/test/cp.js index e8cece026..f898e71dd 100644 --- a/test/cp.js +++ b/test/cp.js @@ -307,7 +307,7 @@ test('recursive, everything exists, no force flag', t => { }); test('-R implies to not follow links', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { shell.cp('-R', 'resources/cp/*', t.context.tmp); t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link t.falsy((fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink())); // this one isn't @@ -325,11 +325,11 @@ test('-R implies to not follow links', t => { shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(), shell.cat(`${t.context.tmp}/fakeLinks/sym.lnk`).toString() ); - } + }); }); test('Missing -R implies -L', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { // Recursive, everything exists, overwrite a real file *by following a link* // Because missing the -R implies -L. shell.cp('-R', 'resources/cp/*', t.context.tmp); @@ -350,7 +350,7 @@ test('Missing -R implies -L', t => { shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(), shell.cat(`${t.context.tmp}/fakeLinks/sym.lnk`).toString() ); - } + }); }); test('recursive, everything exists, with force flag', t => { @@ -411,7 +411,7 @@ test('recursive, with trailing slash, does the exact same', t => { test( 'On Windows, permission bits are quite different so skip those tests for now', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { // preserve mode bits const execBit = parseInt('001', 8); t.is(fs.statSync('resources/cp-mode-bits/executable').mode & execBit, execBit); @@ -420,7 +420,7 @@ test( fs.statSync('resources/cp-mode-bits/executable').mode, fs.statSync(`${t.context.tmp}/executable`).mode ); - } + }); } ); @@ -457,42 +457,42 @@ test('no-recursive will copy regular files only', t => { }); test('-R implies -P', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { shell.cp('-R', 'resources/cp/links/sym.lnk', t.context.tmp); t.truthy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); - } + }); }); test('using -P explicitly works', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { shell.cp('-P', 'resources/cp/links/sym.lnk', t.context.tmp); t.truthy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); - } + }); }); test('using -PR on a link to a folder does not follow the link', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { shell.cp('-PR', 'resources/cp/symFolder', t.context.tmp); t.truthy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink()); - } + }); }); test('-L overrides -P for copying directory', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { shell.cp('-LPR', 'resources/cp/symFolder', t.context.tmp); t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink()); t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder/sym.lnk`).isSymbolicLink()); - } + }); }); test('Recursive, copies entire directory with no symlinks and -L option does not cause change in behavior', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.cp('-rL', 'resources/cp/dir_a', `${t.context.tmp}/dest`); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); t.truthy(fs.existsSync(`${t.context.tmp}/dest/z`)); - } + }); }); test('-u flag won\'t overwrite newer files', t => { diff --git a/test/exec.js b/test/exec.js index f22c73120..07df5ac5b 100644 --- a/test/exec.js +++ b/test/exec.js @@ -5,6 +5,7 @@ import util from 'util'; import test from 'ava'; import shell from '..'; +import utils from './utils/utils'; const CWD = process.cwd(); const ORIG_EXEC_PATH = shell.config.execPath; @@ -138,7 +139,7 @@ test('check process.env works', t => { }); test('set shell option (TODO: add tests for Windows)', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { let result = shell.exec('echo $0'); t.falsy(shell.error()); t.is(result.code, 0); @@ -151,7 +152,7 @@ test('set shell option (TODO: add tests for Windows)', t => { t.is(result.code, 0); t.is(result.stdout, '/bin/bash\n'); } - } + }); }); test('exec returns a ShellString', t => { diff --git a/test/ls.js b/test/ls.js index 89497039e..d2c09a23c 100644 --- a/test/ls.js +++ b/test/ls.js @@ -305,7 +305,7 @@ test('-RA flag, symlinks are not followed', t => { }); test('-RAL flag, follows symlinks', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.ls('-RAL', 'resources/rm'); t.falsy(shell.error()); t.is(result.code, 0); @@ -315,17 +315,17 @@ test('-RAL flag, follows symlinks', t => { t.truthy(result.indexOf('link_to_a_dir/a_file') > -1); t.truthy(result.indexOf('fake.lnk') > -1); t.is(result.length, 5); - } + }); }); test('-L flag, path is symlink', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.ls('-L', 'resources/rm/link_to_a_dir'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.indexOf('a_file') > -1); t.is(result.length, 1); - } + }); }); test('-Rd works like -d', t => { @@ -382,10 +382,10 @@ test('long option, single file', t => { t.is(result.nlink, 1); t.is(result.size, 5); t.truthy(result.mode); // check that these keys exist - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { t.truthy(result.uid); t.truthy(result.gid); - } + }); t.truthy(result.mtime); // check that these keys exist t.truthy(result.atime); // check that these keys exist t.truthy(result.ctime); // check that these keys exist @@ -401,10 +401,10 @@ test('long option, glob files', t => { t.is(result.nlink, 1); t.is(result.size, 5); t.truthy(result.mode); // check that these keys exist - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { t.truthy(result.uid); t.truthy(result.gid); - } + }); t.truthy(result.mtime); // check that these keys exist t.truthy(result.atime); // check that these keys exist t.truthy(result.ctime); // check that these keys exist @@ -423,10 +423,10 @@ test('long option, directory', t => { t.is(result.nlink, 1); t.is(result.size, 5); t.truthy(result.mode); // check that these keys exist - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { t.truthy(result.uid); t.truthy(result.gid); - } + }); t.truthy(result.mtime); // check that these keys exist t.truthy(result.atime); // check that these keys exist t.truthy(result.ctime); // check that these keys exist @@ -446,10 +446,10 @@ test('long option, directory, recursive (and windows converts slashes)', t => { t.is(typeof result.nlink, 'number'); // This can vary between the local machine and travis t.is(typeof result.size, 'number'); // This can vary between different file systems t.truthy(result.mode); // check that these keys exist - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { t.truthy(result.uid); t.truthy(result.gid); - } + }); t.truthy(result.mtime); // check that these keys exist t.truthy(result.atime); // check that these keys exist t.truthy(result.ctime); // check that these keys exist diff --git a/test/mkdir.js b/test/mkdir.js index 4093155d4..f49089a35 100644 --- a/test/mkdir.js +++ b/test/mkdir.js @@ -84,7 +84,7 @@ test('try to make a subdirectory of a file', t => { }); test('Check for invalid permissions', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { // This test case only works on unix, but should work on Windows as well const dirName = 'nowritedir'; shell.mkdir(dirName); @@ -99,7 +99,7 @@ test('Check for invalid permissions', t => { t.truthy(shell.error()); t.falsy(fs.existsSync(dirName + '/foo')); shell.rm('-rf', dirName); // clean up - } + }); }); // diff --git a/test/rm.js b/test/rm.js index e729d2d13..d3228c7e1 100644 --- a/test/rm.js +++ b/test/rm.js @@ -268,7 +268,7 @@ test('remove symbolic link to a dir', t => { }); test('rm -rf on a symbolic link to a dir deletes its contents', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.rm('-rf', `${t.context.tmp}/rm/link_to_a_dir/`); t.falsy(shell.error()); t.is(result.code, 0); @@ -277,18 +277,18 @@ test('rm -rf on a symbolic link to a dir deletes its contents', t => { t.truthy(fs.existsSync(`${t.context.tmp}/rm/link_to_a_dir`)); t.truthy(fs.existsSync(`${t.context.tmp}/rm/a_dir`)); t.falsy(fs.existsSync(`${t.context.tmp}/rm/a_dir/a_file`)); - } + }); }); test('remove broken symbolic link', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { t.truthy(shell.test('-L', `${t.context.tmp}/rm/fake.lnk`)); const result = shell.rm(`${t.context.tmp}/rm/fake.lnk`); t.falsy(shell.error()); t.is(result.code, 0); t.falsy(shell.test('-L', `${t.context.tmp}/rm/fake.lnk`)); t.falsy(fs.existsSync(`${t.context.tmp}/rm/fake.lnk`)); - } + }); }); test('recursive dir removal, for non-normalized path', t => { @@ -301,10 +301,10 @@ test('recursive dir removal, for non-normalized path', t => { }); test('remove fifo', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const fifo = utils.mkfifo(t.context.tmp); const result = shell.rm(fifo); t.falsy(shell.error()); t.is(result.code, 0); - } + }); }); diff --git a/test/test.js b/test/test.js index 39f25795e..cea2094ed 100644 --- a/test/test.js +++ b/test/test.js @@ -1,6 +1,7 @@ import test from 'ava'; import shell from '..'; +import utils from './utils/utils'; shell.config.silent = true; @@ -90,41 +91,41 @@ test('test command is not globbed', t => { // TODO(nate): figure out a way to test links on Windows test('-d option fails for a link', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.test('-d', 'resources/link'); t.falsy(shell.error()); t.falsy(result); - } + }); }); test('-f option succeeds for a link', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.test('-f', 'resources/link'); t.falsy(shell.error()); t.truthy(result); - } + }); }); test('-L option succeeds for a symlink', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.test('-L', 'resources/link'); t.falsy(shell.error()); t.truthy(result); - } + }); }); test('-L option works for broken symlinks', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.test('-L', 'resources/badlink'); t.falsy(shell.error()); t.truthy(result); - } + }); }); test('-L option fails for missing files', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.test('-L', 'resources/404'); t.falsy(shell.error()); t.falsy(result); - } + }); }); diff --git a/test/touch.js b/test/touch.js index ad5dbfd72..70566ea69 100644 --- a/test/touch.js +++ b/test/touch.js @@ -164,11 +164,11 @@ test('file array', t => { }); test('touching broken link creates a new file', t => { - if (process.platform !== 'win32') { + utils.skipOnWin(t, () => { const result = shell.touch('resources/badlink'); t.is(result.code, 0); t.falsy(shell.error()); t.truthy(fs.existsSync('resources/not_existed_file')); shell.rm('resources/not_existed_file'); - } + }); }); diff --git a/test/utils/utils.js b/test/utils/utils.js index a1d313143..aae5cdefb 100644 --- a/test/utils/utils.js +++ b/test/utils/utils.js @@ -1,4 +1,7 @@ const child = require('child_process'); +const path = require('path'); + +const chalk = require('chalk'); const common = require('../../src/common'); @@ -33,7 +36,11 @@ function runScript(script, cb) { exports.runScript = runScript; function sleep(time) { - child.execFileSync(common.config.execPath, ['resources/exec/slow.js', time.toString()]); + const testDirectoryPath = path.dirname(__dirname); + child.execFileSync(common.config.execPath, [ + path.join(testDirectoryPath, 'resources', 'exec', 'slow.js'), + time.toString(), + ]); } exports.sleep = sleep; @@ -46,3 +53,18 @@ function mkfifo(dir) { return null; } exports.mkfifo = mkfifo; + +function skipIfTrue(booleanValue, t, closure) { + if (booleanValue) { + console.warn( + chalk.yellow('Warning: skipping platform-dependent test ') + + chalk.bold.white(`'${t._test.title}'`) + ); + t.truthy(true); // dummy assertion to satisfy ava v0.19+ + } else { + closure(); + } +} + +exports.skipOnUnix = skipIfTrue.bind(module.exports, process.platform !== 'win32'); +exports.skipOnWin = skipIfTrue.bind(module.exports, process.platform === 'win32'); diff --git a/test/which.js b/test/which.js index 705fda311..530fcd2ca 100644 --- a/test/which.js +++ b/test/which.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import utils from './utils/utils'; shell.config.silent = true; @@ -35,7 +36,7 @@ test('basic usage', t => { }); test('Windows can search with or without a .exe extension', t => { - if (process.platform === 'win32') { + utils.skipOnUnix(t, () => { // This should be equivalent on Windows const node = shell.which('node'); const nodeExe = shell.which('node.exe'); @@ -43,7 +44,7 @@ test('Windows can search with or without a .exe extension', t => { // If the paths are equal, then this file *should* exist, since that's // already been checked. t.is(node.toString(), nodeExe.toString()); - } + }); }); test('Searching with -a flag returns an array', t => { From 2ee83ebf7440b695ac78694cbec8a3302d8896ec Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Fri, 11 Aug 2017 11:03:13 -0700 Subject: [PATCH 14/71] refactor(test): update AVA and refactor tests (#760) This updates tests for `AVA` 19.0.0+. `AVA` 0.18.0 has a breaking change which changes the current working directory for tests. As a result, we need to change 'resources' -> 'test/resources' (and similar path changes). `AVA` 0.19.0 has a breaking change that all tests must run at least one assert. This breaking change was already resolved by #746, so no change was necessary in this PR. This updates to `AVA` 0.21.0, since there are no other breaking changes. --- package.json | 2 +- test/cat.js | 12 ++-- test/cd.js | 12 ++-- test/chmod.js | 2 +- test/common.js | 24 +++---- test/config.js | 26 +++---- test/cp.js | 186 ++++++++++++++++++++++++------------------------- test/dirs.js | 6 +- test/exec.js | 6 +- test/find.js | 24 +++---- test/global.js | 4 +- test/grep.js | 34 ++++----- test/head.js | 36 +++++----- test/ln.js | 2 +- test/ls.js | 168 ++++++++++++++++++++++---------------------- test/mkdir.js | 34 ++++----- test/mv.js | 2 +- test/pipe.js | 24 +++---- test/plugin.js | 4 +- test/popd.js | 32 ++++----- test/pushd.js | 162 +++++++++++++++++++++--------------------- test/rm.js | 6 +- test/sed.js | 10 +-- test/set.js | 12 ++-- test/sort.js | 34 ++++----- test/tail.js | 30 ++++---- test/test.js | 30 ++++---- test/touch.js | 6 +- test/uniq.js | 44 ++++++------ 29 files changed, 487 insertions(+), 487 deletions(-) diff --git a/package.json b/package.json index eab128b74..6303ffe1c 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "rechoir": "^0.6.2" }, "devDependencies": { - "ava": "^0.16.0", + "ava": "^0.21.0", "chalk": "^1.1.3", "codecov": "^1.0.1", "coffee-script": "^1.10.0", diff --git a/test/cat.js b/test/cat.js index 53bd52257..c61905f6a 100644 --- a/test/cat.js +++ b/test/cat.js @@ -26,10 +26,10 @@ test('nonexistent file', t => { }); test('directory', t => { - const result = shell.cat('resources/cat'); + const result = shell.cat('test/resources/cat'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, 'cat: resources/cat: Is a directory'); + t.is(result.stderr, 'cat: test/resources/cat: Is a directory'); }); // @@ -37,28 +37,28 @@ test('directory', t => { // test('simple', t => { - const result = shell.cat('resources/cat/file1'); + const result = shell.cat('test/resources/cat/file1'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), 'test1\n'); }); test('multiple files', t => { - const result = shell.cat('resources/cat/file2', 'resources/cat/file1'); + const result = shell.cat('test/resources/cat/file2', 'test/resources/cat/file1'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), 'test2\ntest1\n'); }); test('multiple files, array syntax', t => { - const result = shell.cat(['resources/cat/file2', 'resources/cat/file1']); + const result = shell.cat(['test/resources/cat/file2', 'test/resources/cat/file1']); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), 'test2\ntest1\n'); }); test('glob', t => { - const result = shell.cat('resources/file*.txt'); + const result = shell.cat('test/resources/file*.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.search('test1') > -1); // file order might be random diff --git a/test/cd.js b/test/cd.js index 3c15b1a3d..c472973da 100644 --- a/test/cd.js +++ b/test/cd.js @@ -34,11 +34,11 @@ test('nonexistent directory', t => { }); test('file not dir', t => { - t.truthy(fs.existsSync('resources/file1')); // sanity check - const result = shell.cd('resources/file1'); // file, not dir + t.truthy(fs.existsSync('test/resources/file1')); // sanity check + const result = shell.cd('test/resources/file1'); // file, not dir t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, 'cd: not a directory: resources/file1'); + t.is(result.stderr, 'cd: not a directory: test/resources/file1'); }); test('no previous dir', t => { @@ -76,13 +76,13 @@ test('previous directory (-)', t => { test('cd + other commands', t => { t.falsy(fs.existsSync(`${t.context.tmp}/file1`)); - let result = shell.cd('resources'); + let result = shell.cd('test/resources'); t.falsy(shell.error()); t.is(result.code, 0); - result = shell.cp('file1', `../${t.context.tmp}`); + result = shell.cp('file1', `../../${t.context.tmp}`); t.falsy(shell.error()); t.is(result.code, 0); - result = shell.cd(`../${t.context.tmp}`); + result = shell.cd(`../../${t.context.tmp}`); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(fs.existsSync('file1')); diff --git a/test/chmod.js b/test/chmod.js index 60e09ff14..7b617ab3a 100644 --- a/test/chmod.js +++ b/test/chmod.js @@ -10,7 +10,7 @@ const BITMASK = parseInt('777', 8); test.before(() => { TMP = utils.getTempDir(); - shell.cp('-r', 'resources', TMP); + shell.cp('-r', 'test/resources', TMP); shell.config.silent = true; }); diff --git a/test/common.js b/test/common.js index b59f7a267..7f8fb1364 100644 --- a/test/common.js +++ b/test/common.js @@ -23,7 +23,7 @@ test('too few args', t => { test('should be a list', t => { t.throws(() => { - common.expand('resources'); + common.expand('test/resources'); }, TypeError); }); @@ -138,36 +138,36 @@ test('convertErrorOutput: changes backslashes to forward slashes', t => { // common.expand() // test('single file, array syntax', t => { - const result = common.expand(['resources/file1.txt']); + const result = common.expand(['test/resources/file1.txt']); t.falsy(shell.error()); - t.deepEqual(result, ['resources/file1.txt']); + t.deepEqual(result, ['test/resources/file1.txt']); }); test('multiple file, glob syntax, * for file name', t => { - const result = common.expand(['resources/file*.txt']); + const result = common.expand(['test/resources/file*.txt']); t.falsy(shell.error()); - t.deepEqual(result.sort(), ['resources/file1.txt', 'resources/file2.txt'].sort()); + t.deepEqual(result.sort(), ['test/resources/file1.txt', 'test/resources/file2.txt'].sort()); }); test('multiple file, glob syntax, * for directory name', t => { - const result = common.expand(['r*/file*.txt']); + const result = common.expand(['test/r*/file*.txt']); t.falsy(shell.error()); - t.deepEqual(result.sort(), ['resources/file1.txt', 'resources/file2.txt'].sort()); + t.deepEqual(result.sort(), ['test/resources/file1.txt', 'test/resources/file2.txt'].sort()); }); test('multiple file, glob syntax, ** for directory name', t => { - const result = common.expand(['resources/**/file*.js']); + const result = common.expand(['test/resources/**/file*.js']); t.falsy(shell.error()); t.deepEqual( result.sort(), - ['resources/file1.js', 'resources/file2.js', 'resources/ls/file1.js', 'resources/ls/file2.js'].sort() + ['test/resources/file1.js', 'test/resources/file2.js', 'test/resources/ls/file1.js', 'test/resources/ls/file2.js'].sort() ); }); test('broken links still expand', t => { - const result = common.expand(['resources/b*dlink']); + const result = common.expand(['test/resources/b*dlink']); t.falsy(shell.error()); - t.deepEqual(result, ['resources/badlink']); + t.deepEqual(result, ['test/resources/badlink']); }); test('empty array', t => { @@ -285,7 +285,7 @@ test('Some basic tests on the ShellString type', t => { }); test.cb('Commands that fail will still output error messages to stderr', t => { - const script = 'require(\'../global\'); ls(\'noexist\'); cd(\'noexist\');'; + const script = 'require(\'./global\'); ls(\'noexist\'); cd(\'noexist\');'; utils.runScript(script, (err, stdout, stderr) => { t.is(stdout, ''); t.is( diff --git a/test/config.js b/test/config.js index 83c45ffda..743df3561 100644 --- a/test/config.js +++ b/test/config.js @@ -32,7 +32,7 @@ test('config.silent can be set to false', t => { test.cb('config.fatal = false', t => { t.falsy(shell.config.fatal); - const script = 'require(\'../global.js\'); config.silent=true; config.fatal=false; cp("this_file_doesnt_exist", "."); echo("got here");'; + const script = 'require(\'./global.js\'); config.silent=true; config.fatal=false; cp("this_file_doesnt_exist", "."); echo("got here");'; utils.runScript(script, (err, stdout) => { t.truthy(stdout.match('got here')); t.end(); @@ -40,7 +40,7 @@ test.cb('config.fatal = false', t => { }); test.cb('config.fatal = true', t => { - const script = 'require(\'../global.js\'); config.silent=true; config.fatal=true; cp("this_file_doesnt_exist", "."); echo("got here");'; + const script = 'require(\'./global.js\'); config.silent=true; config.fatal=true; cp("this_file_doesnt_exist", "."); echo("got here");'; utils.runScript(script, (err, stdout) => { t.falsy(stdout.match('got here')); t.end(); @@ -52,24 +52,24 @@ test.cb('config.fatal = true', t => { // test('Expands to directories by default', t => { - const result = common.expand(['resources/*a*']); + const result = common.expand(['test/resources/*a*']); t.is(result.length, 5); - t.truthy(result.indexOf('resources/a.txt') > -1); - t.truthy(result.indexOf('resources/badlink') > -1); - t.truthy(result.indexOf('resources/cat') > -1); - t.truthy(result.indexOf('resources/head') > -1); - t.truthy(result.indexOf('resources/external') > -1); + t.truthy(result.indexOf('test/resources/a.txt') > -1); + t.truthy(result.indexOf('test/resources/badlink') > -1); + t.truthy(result.indexOf('test/resources/cat') > -1); + t.truthy(result.indexOf('test/resources/head') > -1); + t.truthy(result.indexOf('test/resources/external') > -1); }); test( 'Check to make sure options get passed through (nodir is an example)', t => { shell.config.globOptions = { nodir: true }; - const result = common.expand(['resources/*a*']); + const result = common.expand(['test/resources/*a*']); t.is(result.length, 2); - t.truthy(result.indexOf('resources/a.txt') > -1); - t.truthy(result.indexOf('resources/badlink') > -1); - t.truthy(result.indexOf('resources/cat') < 0); - t.truthy(result.indexOf('resources/external') < 0); + t.truthy(result.indexOf('test/resources/a.txt') > -1); + t.truthy(result.indexOf('test/resources/badlink') > -1); + t.truthy(result.indexOf('test/resources/cat') < 0); + t.truthy(result.indexOf('test/resources/external') < 0); } ); diff --git a/test/cp.js b/test/cp.js index f898e71dd..34b81c7e9 100644 --- a/test/cp.js +++ b/test/cp.js @@ -46,7 +46,7 @@ test('only an option', t => { }); test('invalid option', t => { - const result = shell.cp('-@', 'resources/file1', `${t.context.tmp}/file1`); + const result = shell.cp('-@', 'test/resources/file1', `${t.context.tmp}/file1`); t.truthy(shell.error()); t.is(result.code, 1); t.falsy(fs.existsSync(`${t.context.tmp}/file1`)); @@ -84,14 +84,14 @@ test('multiple sources do not exist', t => { }); test('too many sources', t => { - const result = shell.cp('asdfasdf1', 'asdfasdf2', 'resources/file1'); + const result = shell.cp('asdfasdf1', 'asdfasdf2', 'test/resources/file1'); t.truthy(shell.error()); t.is(result.code, 1); t.is(result.stderr, 'cp: dest is not a directory (too many sources)'); }); test('too many sources #2', t => { - const result = shell.cp('resources/file1', 'resources/file2', `${t.context.tmp}/a_file`); + const result = shell.cp('test/resources/file1', 'test/resources/file2', `${t.context.tmp}/a_file`); t.truthy(shell.error()); t.is(result.code, 1); t.falsy(fs.existsSync(`${t.context.tmp}/a_file`)); @@ -110,12 +110,12 @@ test('empty string source', t => { // test('dest already exists', t => { - const oldContents = shell.cat('resources/file2').toString(); - const result = shell.cp('-n', 'resources/file1', 'resources/file2'); + const oldContents = shell.cat('test/resources/file2').toString(); + const result = shell.cp('-n', 'test/resources/file1', 'test/resources/file2'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.stderr, ''); - t.is(shell.cat('resources/file2').toString(), oldContents); + t.is(shell.cat('test/resources/file2').toString(), oldContents); }); test('-nR does not overwrite an existing file at the destination', t => { @@ -125,8 +125,8 @@ test('-nR does not overwrite an existing file at the destination', t => { const oldContents = 'original content'; shell.ShellString(oldContents).to(`${dest}/a`); - // Attempt to overwrite /tmp/new/cp/ with resources/cp/ - const result = shell.cp('-nR', 'resources/cp/', `${t.context.tmp}/new/`); + // Attempt to overwrite /tmp/new/cp/ with test/resources/cp/ + const result = shell.cp('-nR', 'test/resources/cp/', `${t.context.tmp}/new/`); t.falsy(shell.error()); t.is(result.code, 0); t.falsy(result.stderr); @@ -135,9 +135,9 @@ test('-nR does not overwrite an existing file at the destination', t => { test('-n does not overwrite an existing file if the destination is a directory', t => { const oldContents = 'original content'; - shell.cp('resources/file1', `${t.context.tmp}`); + shell.cp('test/resources/file1', `${t.context.tmp}`); new shell.ShellString(oldContents).to(`${t.context.tmp}/file1`); - const result = shell.cp('-n', 'resources/file1', `${t.context.tmp}`); + const result = shell.cp('-n', 'test/resources/file1', `${t.context.tmp}`); t.falsy(shell.error()); t.is(result.code, 0); t.falsy(result.stderr); @@ -145,30 +145,30 @@ test('-n does not overwrite an existing file if the destination is a directory', }); test('-f by default', t => { - shell.cp('resources/file2', 'resources/copyfile2'); - const result = shell.cp('resources/file1', 'resources/file2'); // dest already exists + shell.cp('test/resources/file2', 'test/resources/copyfile2'); + const result = shell.cp('test/resources/file1', 'test/resources/file2'); // dest already exists t.falsy(shell.error()); t.is(result.code, 0); t.falsy(result.stderr); - t.is(shell.cat('resources/file1').toString(), shell.cat('resources/file2').toString()); // after cp - shell.mv('resources/copyfile2', 'resources/file2'); // restore + t.is(shell.cat('test/resources/file1').toString(), shell.cat('test/resources/file2').toString()); // after cp + shell.mv('test/resources/copyfile2', 'test/resources/file2'); // restore t.falsy(shell.error()); }); test('-f (explicitly)', t => { - shell.cp('resources/file2', 'resources/copyfile2'); - const result = shell.cp('-f', 'resources/file1', 'resources/file2'); // dest already exists + shell.cp('test/resources/file2', 'test/resources/copyfile2'); + const result = shell.cp('-f', 'test/resources/file1', 'test/resources/file2'); // dest already exists t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); - t.is(shell.cat('resources/file1').toString(), shell.cat('resources/file2').toString()); // after cp - shell.mv('resources/copyfile2', 'resources/file2'); // restore + t.is(shell.cat('test/resources/file1').toString(), shell.cat('test/resources/file2').toString()); // after cp + shell.mv('test/resources/copyfile2', 'test/resources/file2'); // restore t.falsy(shell.error()); t.is(result.code, 0); }); test('simple - to dir', t => { - const result = shell.cp('resources/file1', t.context.tmp); + const result = shell.cp('test/resources/file1', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -176,7 +176,7 @@ test('simple - to dir', t => { }); test('simple - to file', t => { - const result = shell.cp('resources/file2', `${t.context.tmp}/file2`); + const result = shell.cp('test/resources/file2', `${t.context.tmp}/file2`); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -184,7 +184,7 @@ test('simple - to file', t => { }); test('simple - file list', t => { - const result = shell.cp('resources/file1', 'resources/file2', t.context.tmp); + const result = shell.cp('test/resources/file1', 'test/resources/file2', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -193,7 +193,7 @@ test('simple - file list', t => { }); test('simple - file list, array syntax', t => { - const result = shell.cp(['resources/file1', 'resources/file2'], t.context.tmp); + const result = shell.cp(['test/resources/file1', 'test/resources/file2'], t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -202,9 +202,9 @@ test('simple - file list, array syntax', t => { }); test('-f option', t => { - shell.cp('resources/file2', `${t.context.tmp}/file3`); + shell.cp('test/resources/file2', `${t.context.tmp}/file3`); t.truthy(fs.existsSync(`${t.context.tmp}/file3`)); - const result = shell.cp('-f', 'resources/file2', `${t.context.tmp}/file3`); // file exists, but -f specified + const result = shell.cp('-f', 'test/resources/file2', `${t.context.tmp}/file3`); // file exists, but -f specified t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -212,7 +212,7 @@ test('-f option', t => { }); test('glob', t => { - const result = shell.cp('resources/file?', t.context.tmp); + const result = shell.cp('test/resources/file?', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -226,7 +226,7 @@ test('glob', t => { test('wildcard', t => { shell.rm(`${t.context.tmp}/file1`, `${t.context.tmp}/file2`); - const result = shell.cp('resources/file*', t.context.tmp); + const result = shell.cp('test/resources/file*', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -239,7 +239,7 @@ test('wildcard', t => { }); test('recursive, with regular files', t => { - const result = shell.cp('-R', 'resources/file1', 'resources/file2', t.context.tmp); + const result = shell.cp('-R', 'test/resources/file1', 'test/resources/file2', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -248,37 +248,37 @@ test('recursive, with regular files', t => { }); test('omit directory if missing recursive flag', t => { - const result = shell.cp('resources/cp', t.context.tmp); - t.is(shell.error(), "cp: omitting directory 'resources/cp'"); - t.is(result.stderr, "cp: omitting directory 'resources/cp'"); + const result = shell.cp('test/resources/cp', t.context.tmp); + t.is(shell.error(), "cp: omitting directory 'test/resources/cp'"); + t.is(result.stderr, "cp: omitting directory 'test/resources/cp'"); t.is(result.code, 1); t.falsy(fs.existsSync(`${t.context.tmp}/file1`)); t.falsy(fs.existsSync(`${t.context.tmp}/file2`)); }); test('recursive, nothing exists', t => { - const result = shell.cp('-R', 'resources/cp', t.context.tmp); + const result = shell.cp('-R', 'test/resources/cp', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); - t.is(shell.ls('-R', 'resources/cp').toString(), shell.ls('-R', `${t.context.tmp}/cp`).toString()); + t.is(shell.ls('-R', 'test/resources/cp').toString(), shell.ls('-R', `${t.context.tmp}/cp`).toString()); }); test( 'recursive, nothing exists, source ends in \'/\' (see Github issue #15)', t => { - const result = shell.cp('-R', 'resources/cp/', `${t.context.tmp}/`); + const result = shell.cp('-R', 'test/resources/cp/', `${t.context.tmp}/`); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); - t.is(shell.ls('-R', 'resources/cp').toString(), shell.ls('-R', `${t.context.tmp}/cp`).toString()); + t.is(shell.ls('-R', 'test/resources/cp').toString(), shell.ls('-R', `${t.context.tmp}/cp`).toString()); } ); test( 'recursive, globbing regular files with extension (see Github issue #376)', t => { - const result = shell.cp('-R', 'resources/file*.txt', t.context.tmp); + const result = shell.cp('-R', 'test/resources/file*.txt', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -290,7 +290,7 @@ test( test( 'recursive, copying one regular file (also related to Github issue #376)', t => { - const result = shell.cp('-R', 'resources/file1.txt', t.context.tmp); + const result = shell.cp('-R', 'test/resources/file1.txt', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -300,7 +300,7 @@ test( ); test('recursive, everything exists, no force flag', t => { - const result = shell.cp('-R', 'resources/cp', t.context.tmp); + const result = shell.cp('-R', 'test/resources/cp', t.context.tmp); t.falsy(shell.error()); // crash test only t.falsy(result.stderr); t.is(result.code, 0); @@ -308,7 +308,7 @@ test('recursive, everything exists, no force flag', t => { test('-R implies to not follow links', t => { utils.skipOnWin(t, () => { - shell.cp('-R', 'resources/cp/*', t.context.tmp); + shell.cp('-R', 'test/resources/cp/*', t.context.tmp); t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link t.falsy((fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink())); // this one isn't t.not( @@ -332,7 +332,7 @@ test('Missing -R implies -L', t => { utils.skipOnWin(t, () => { // Recursive, everything exists, overwrite a real file *by following a link* // Because missing the -R implies -L. - shell.cp('-R', 'resources/cp/*', t.context.tmp); + shell.cp('-R', 'test/resources/cp/*', t.context.tmp); t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link t.falsy((fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink())); // this one isn't t.not( @@ -354,26 +354,26 @@ test('Missing -R implies -L', t => { }); test('recursive, everything exists, with force flag', t => { - let result = shell.cp('-R', 'resources/cp', t.context.tmp); + let result = shell.cp('-R', 'test/resources/cp', t.context.tmp); shell.ShellString('changing things around').to(`${t.context.tmp}/cp/dir_a/z`); - t.not(shell.cat('resources/cp/dir_a/z').toString(), shell.cat(`${t.context.tmp}/cp/dir_a/z`).toString()); // before cp - result = shell.cp('-Rf', 'resources/cp', t.context.tmp); + t.not(shell.cat('test/resources/cp/dir_a/z').toString(), shell.cat(`${t.context.tmp}/cp/dir_a/z`).toString()); // before cp + result = shell.cp('-Rf', 'test/resources/cp', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); - t.is(shell.cat('resources/cp/dir_a/z').toString(), shell.cat(`${t.context.tmp}/cp/dir_a/z`).toString()); // after cp + t.is(shell.cat('test/resources/cp/dir_a/z').toString(), shell.cat(`${t.context.tmp}/cp/dir_a/z`).toString()); // after cp }); test( 'recursive, creates dest dir since it\'s only one level deep (see Github issue #44)', t => { - const result = shell.cp('-r', 'resources/issue44', `${t.context.tmp}/dir2`); + const result = shell.cp('-r', 'test/resources/issue44', `${t.context.tmp}/dir2`); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); - t.is(shell.ls('-R', 'resources/issue44').toString(), shell.ls('-R', `${t.context.tmp}/dir2`).toString()); + t.is(shell.ls('-R', 'test/resources/issue44').toString(), shell.ls('-R', `${t.context.tmp}/dir2`).toString()); t.is( - shell.cat('resources/issue44/main.js').toString(), + shell.cat('test/resources/issue44/main.js').toString(), shell.cat(`${t.context.tmp}/dir2/main.js`).toString() ); } @@ -382,7 +382,7 @@ test( test( 'recursive, does *not* create dest dir since it\'s too deep (see Github issue #44)', t => { - const result = shell.cp('-r', 'resources/issue44', `${t.context.tmp}/dir2/dir3`); + const result = shell.cp('-r', 'test/resources/issue44', `${t.context.tmp}/dir2/dir3`); t.truthy(shell.error()); t.is( result.stderr, @@ -394,7 +394,7 @@ test( ); test('recursive, copies entire directory', t => { - const result = shell.cp('-r', 'resources/cp/dir_a', `${t.context.tmp}/dest`); + const result = shell.cp('-r', 'test/resources/cp/dir_a', `${t.context.tmp}/dest`); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -402,7 +402,7 @@ test('recursive, copies entire directory', t => { }); test('recursive, with trailing slash, does the exact same', t => { - const result = shell.cp('-r', 'resources/cp/dir_a/', `${t.context.tmp}/dest`); + const result = shell.cp('-r', 'test/resources/cp/dir_a/', `${t.context.tmp}/dest`); t.is(result.code, 0); t.falsy(shell.error()); t.truthy(fs.existsSync(`${t.context.tmp}/dest/z`)); @@ -414,10 +414,10 @@ test( utils.skipOnWin(t, () => { // preserve mode bits const execBit = parseInt('001', 8); - t.is(fs.statSync('resources/cp-mode-bits/executable').mode & execBit, execBit); - shell.cp('resources/cp-mode-bits/executable', `${t.context.tmp}/executable`); + t.is(fs.statSync('test/resources/cp-mode-bits/executable').mode & execBit, execBit); + shell.cp('test/resources/cp-mode-bits/executable', `${t.context.tmp}/executable`); t.is( - fs.statSync('resources/cp-mode-bits/executable').mode, + fs.statSync('test/resources/cp-mode-bits/executable').mode, fs.statSync(`${t.context.tmp}/executable`).mode ); }); @@ -426,7 +426,7 @@ test( test('Make sure hidden files are copied recursively', t => { shell.rm('-rf', t.context.tmp); - const result = shell.cp('-r', 'resources/ls/', t.context.tmp); + const result = shell.cp('-r', 'test/resources/ls/', t.context.tmp); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -434,7 +434,7 @@ test('Make sure hidden files are copied recursively', t => { }); test('no-recursive will copy regular files only', t => { - const result = shell.cp('resources/file1.txt', 'resources/ls/', t.context.tmp); + const result = shell.cp('test/resources/file1.txt', 'test/resources/ls/', t.context.tmp); t.is(result.code, 1); t.truthy(shell.error()); t.falsy(fs.existsSync(`${t.context.tmp}/.hidden_file`)); // doesn't copy dir contents @@ -443,8 +443,8 @@ test('no-recursive will copy regular files only', t => { }); test('no-recursive will copy regular files only', t => { - const result = shell.cp('resources/file1.txt', 'resources/file2.txt', 'resources/cp', - 'resources/ls/', t.context.tmp); + const result = shell.cp('test/resources/file1.txt', 'test/resources/file2.txt', 'test/resources/cp', + 'test/resources/ls/', t.context.tmp); t.is(result.code, 1); t.truthy(shell.error()); @@ -458,28 +458,28 @@ test('no-recursive will copy regular files only', t => { test('-R implies -P', t => { utils.skipOnWin(t, () => { - shell.cp('-R', 'resources/cp/links/sym.lnk', t.context.tmp); + shell.cp('-R', 'test/resources/cp/links/sym.lnk', t.context.tmp); t.truthy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); }); test('using -P explicitly works', t => { utils.skipOnWin(t, () => { - shell.cp('-P', 'resources/cp/links/sym.lnk', t.context.tmp); + shell.cp('-P', 'test/resources/cp/links/sym.lnk', t.context.tmp); t.truthy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); }); test('using -PR on a link to a folder does not follow the link', t => { utils.skipOnWin(t, () => { - shell.cp('-PR', 'resources/cp/symFolder', t.context.tmp); + shell.cp('-PR', 'test/resources/cp/symFolder', t.context.tmp); t.truthy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink()); }); }); test('-L overrides -P for copying directory', t => { utils.skipOnWin(t, () => { - shell.cp('-LPR', 'resources/cp/symFolder', t.context.tmp); + shell.cp('-LPR', 'test/resources/cp/symFolder', t.context.tmp); t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink()); t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder/sym.lnk`).isSymbolicLink()); }); @@ -487,7 +487,7 @@ test('-L overrides -P for copying directory', t => { test('Recursive, copies entire directory with no symlinks and -L option does not cause change in behavior', t => { utils.skipOnWin(t, () => { - const result = shell.cp('-rL', 'resources/cp/dir_a', `${t.context.tmp}/dest`); + const result = shell.cp('-rL', 'test/resources/cp/dir_a', `${t.context.tmp}/dest`); t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); @@ -497,23 +497,23 @@ test('Recursive, copies entire directory with no symlinks and -L option does not test('-u flag won\'t overwrite newer files', t => { shell.touch(`${t.context.tmp}/file1.js`); - shell.cp('-u', 'resources/file1.js', t.context.tmp); + shell.cp('-u', 'test/resources/file1.js', t.context.tmp); t.falsy(shell.error()); - t.not(shell.cat('resources/file1.js').toString(), shell.cat(`${t.context.tmp}/file1.js`).toString()); + t.not(shell.cat('test/resources/file1.js').toString(), shell.cat(`${t.context.tmp}/file1.js`).toString()); }); test('-u flag does overwrite older files', t => { shell.touch({ '-d': new Date(10) }, `${t.context.tmp}/file1.js`); // really old file - shell.cp('-u', 'resources/file1.js', t.context.tmp); + shell.cp('-u', 'test/resources/file1.js', t.context.tmp); t.falsy(shell.error()); - t.is(shell.cat('resources/file1.js').toString(), shell.cat(`${t.context.tmp}/file1.js`).toString()); + t.is(shell.cat('test/resources/file1.js').toString(), shell.cat(`${t.context.tmp}/file1.js`).toString()); }); test('-u flag works even if it\'s not overwriting a file', t => { t.falsy(fs.existsSync(`${t.context.tmp}/file1.js`)); - shell.cp('-u', 'resources/file1.js', t.context.tmp); + shell.cp('-u', 'test/resources/file1.js', t.context.tmp); t.falsy(shell.error()); - t.is(shell.cat('resources/file1.js').toString(), shell.cat(`${t.context.tmp}/file1.js`).toString()); + t.is(shell.cat('test/resources/file1.js').toString(), shell.cat(`${t.context.tmp}/file1.js`).toString()); }); test('-u flag works correctly recursively', t => { @@ -536,34 +536,34 @@ test('-u flag works correctly recursively', t => { }); test('using -R on a link to a folder *does* follow the link', t => { - shell.cp('-R', 'resources/cp/symFolder', t.context.tmp); + shell.cp('-R', 'test/resources/cp/symFolder', t.context.tmp); t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink()); }); test('Without -R, -L is implied', t => { - shell.cp('resources/cp/links/sym.lnk', t.context.tmp); + shell.cp('test/resources/cp/links/sym.lnk', t.context.tmp); t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); test('-L explicitly works', t => { - shell.cp('-L', 'resources/cp/links/sym.lnk', t.context.tmp); + shell.cp('-L', 'test/resources/cp/links/sym.lnk', t.context.tmp); t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); test('using -LR does not imply -P', t => { - shell.cp('-LR', 'resources/cp/links/sym.lnk', t.context.tmp); + shell.cp('-LR', 'test/resources/cp/links/sym.lnk', t.context.tmp); t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); test('using -LR also works recursively on directories containing links', t => { - shell.cp('-LR', 'resources/cp/links', t.context.tmp); + shell.cp('-LR', 'test/resources/cp/links', t.context.tmp); t.falsy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); }); test('-L always overrides a -P', t => { - shell.cp('-LP', 'resources/cp/links/sym.lnk', t.context.tmp); + shell.cp('-LP', 'test/resources/cp/links/sym.lnk', t.context.tmp); t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); - shell.cp('-LPR', 'resources/cp/links/sym.lnk', t.context.tmp); + shell.cp('-LPR', 'test/resources/cp/links/sym.lnk', t.context.tmp); t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); @@ -623,7 +623,7 @@ test('cp -L follows symlinks', t => { utils.skipOnWinForEPERM(shell.ln.bind(shell, '-s', `${t.context.tmp}/0`, `${t.context.tmp}/symlinktest`), () => { shell.mkdir('-p', `${t.context.tmp}/sub`); shell.mkdir('-p', `${t.context.tmp}/new`); - shell.cp('-f', 'resources/file1.txt', `${t.context.tmp}/sub/file.txt`); + shell.cp('-f', 'test/resources/file1.txt', `${t.context.tmp}/sub/file.txt`); shell.cd(`${t.context.tmp}/sub`); shell.ln('-s', 'file.txt', 'foo.lnk'); shell.ln('-s', 'file.txt', 'sym.lnk'); @@ -631,7 +631,7 @@ test('cp -L follows symlinks', t => { shell.cp('-L', 'sub/*', 'new/'); shell.cd('new'); - shell.cp('-f', '../../resources/file2.txt', 'file.txt'); + shell.cp('-f', '../../test/resources/file2.txt', 'file.txt'); t.is(shell.cat('file.txt').toString(), 'test2\n'); // Ensure other files have not changed. t.is(shell.cat('foo.lnk').toString(), 'test1\n'); @@ -645,8 +645,8 @@ test('cp -L follows symlinks', t => { test('Test with recursive option and symlinks.', t => { utils.skipOnWinForEPERM(shell.ln.bind(shell, '-s', `${t.context.tmp}/0`, `${t.context.tmp}/symlinktest`), () => { shell.mkdir('-p', `${t.context.tmp}/sub/sub1`); - shell.cp('-f', 'resources/file1.txt', `${t.context.tmp}/sub/file.txt`); - shell.cp('-f', 'resources/file1.txt', `${t.context.tmp}/sub/sub1/file.txt`); + shell.cp('-f', 'test/resources/file1.txt', `${t.context.tmp}/sub/file.txt`); + shell.cp('-f', 'test/resources/file1.txt', `${t.context.tmp}/sub/sub1/file.txt`); shell.cd(`${t.context.tmp}/sub`); shell.ln('-s', 'file.txt', 'foo.lnk'); shell.ln('-s', 'file.txt', 'sym.lnk'); @@ -665,7 +665,7 @@ test('Test with recursive option and symlinks.', t => { shell.cd('new'); // Ensure copies of files are symlinks by updating file contents. - shell.cp('-f', '../../resources/file2.txt', 'file.txt'); + shell.cp('-f', '../../test/resources/file2.txt', 'file.txt'); t.is(shell.cat('file.txt').toString(), 'test2\n'); // Ensure other files have not changed. t.is(shell.cat('foo.lnk').toString(), 'test1\n'); @@ -677,7 +677,7 @@ test('Test with recursive option and symlinks.', t => { // Ensure other files have not changed. shell.cd('sub1'); - shell.cp('-f', '../../../resources/file2.txt', 'file.txt'); + shell.cp('-f', '../../../test/resources/file2.txt', 'file.txt'); t.is(shell.cat('file.txt').toString(), 'test2\n'); t.is(shell.cat('foo.lnk').toString(), 'test1\n'); t.is(shell.cat('sym.lnk').toString(), 'test1\n'); @@ -689,39 +689,39 @@ test('Test with recursive option and symlinks.', t => { }); test('recursive, with a non-normalized path', t => { - const result = shell.cp('-R', 'resources/../resources/./cp', t.context.tmp); + const result = shell.cp('-R', 'test/resources/../resources/./cp', t.context.tmp); t.falsy(shell.error()); // crash test only t.falsy(result.stderr); t.is(result.code, 0); }); test('copy file to same path', t => { - const result = shell.cp('resources/file1', 'resources/file1'); + const result = shell.cp('test/resources/file1', 'test/resources/file1'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, "cp: 'resources/file1' and 'resources/file1' are the same file"); + t.is(result.stderr, "cp: 'test/resources/file1' and 'test/resources/file1' are the same file"); }); test('copy file to same directory', t => { - const result = shell.cp('resources/file1', 'resources'); + const result = shell.cp('test/resources/file1', 'test/resources'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, "cp: 'resources/file1' and 'resources/file1' are the same file"); + t.is(result.stderr, "cp: 'test/resources/file1' and 'test/resources/file1' are the same file"); }); test('copy mutliple files to same location', t => { - const result = shell.cp('resources/file1', 'resources/file2', 'resources'); + const result = shell.cp('test/resources/file1', 'test/resources/file2', 'test/resources'); t.truthy(shell.error()); t.is(result.code, 1); t.is( result.stderr, - "cp: 'resources/file1' and 'resources/file1' are the same file\n" + - "cp: 'resources/file2' and 'resources/file2' are the same file" + "cp: 'test/resources/file1' and 'test/resources/file1' are the same file\n" + + "cp: 'test/resources/file2' and 'test/resources/file2' are the same file" ); }); test('should not overwrite recently created files', t => { - const result = shell.cp('resources/file1', 'resources/cp/file1', t.context.tmp); + const result = shell.cp('test/resources/file1', 'test/resources/cp/file1', t.context.tmp); t.truthy(shell.error()); t.is(result.code, 1); @@ -729,13 +729,13 @@ test('should not overwrite recently created files', t => { t.is(shell.cat(`${t.context.tmp}/file1`).toString(), 'test1'); t.is( result.stderr, - `cp: will not overwrite just-created '${t.context.tmp}/file1' with 'resources/cp/file1'` + `cp: will not overwrite just-created '${t.context.tmp}/file1' with 'test/resources/cp/file1'` ); }); test('should not overwrite recently created files (in recursive Mode)', t => { - const result = shell.cp('-R', 'resources/file1', 'resources/cp/file1', t.context.tmp); + const result = shell.cp('-R', 'test/resources/file1', 'test/resources/cp/file1', t.context.tmp); t.truthy(shell.error()); t.is(result.code, 1); @@ -743,12 +743,12 @@ test('should not overwrite recently created files (in recursive Mode)', t => { t.is(shell.cat(`${t.context.tmp}/file1`).toString(), 'test1'); t.is( result.stderr, - `cp: will not overwrite just-created '${t.context.tmp}/file1' with 'resources/cp/file1'` + `cp: will not overwrite just-created '${t.context.tmp}/file1' with 'test/resources/cp/file1'` ); }); test('should not overwrite recently created files (not give error no-force mode)', t => { - const result = shell.cp('-n', 'resources/file1', 'resources/cp/file1', t.context.tmp); + const result = shell.cp('-n', 'test/resources/file1', 'test/resources/cp/file1', t.context.tmp); t.falsy(shell.error()); t.is(result.code, 0); diff --git a/test/dirs.js b/test/dirs.js index 085a1294f..10d6e4d7f 100644 --- a/test/dirs.js +++ b/test/dirs.js @@ -6,7 +6,7 @@ import shell from '..'; test.beforeEach(() => { shell.config.resetForTesting(); - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); }); @@ -15,8 +15,8 @@ test.beforeEach(() => { // const trail = [ - path.resolve(path.resolve(), 'resources/pushd/a'), - path.resolve(path.resolve(), 'resources/pushd'), + path.resolve(path.resolve(), 'test/resources/pushd/a'), + path.resolve(path.resolve(), 'test/resources/pushd'), path.resolve(), ]; diff --git a/test/exec.js b/test/exec.js index 07df5ac5b..e2e8bd1cf 100644 --- a/test/exec.js +++ b/test/exec.js @@ -86,7 +86,7 @@ test('check exit code', t => { }); test('interaction with cd', t => { - shell.cd('resources/external'); + shell.cd('test/resources/external'); const result = shell.exec(`${JSON.stringify(shell.config.execPath)} node_script.js`); t.falsy(shell.error()); t.is(result.code, 0); @@ -118,12 +118,12 @@ test('set maxBuffer (very small)', t => { }); test('set timeout option', t => { - const result = shell.exec(`${JSON.stringify(shell.config.execPath)} resources/exec/slow.js 100`); // default timeout is ok + const result = shell.exec(`${JSON.stringify(shell.config.execPath)} test/resources/exec/slow.js 100`); // default timeout is ok t.falsy(shell.error()); t.is(result.code, 0); if (process.version >= 'v0.11') { // this option doesn't work on v0.10 - shell.exec(`${JSON.stringify(shell.config.execPath)} resources/exec/slow.js 100`, { timeout: 10 }); // times out + shell.exec(`${JSON.stringify(shell.config.execPath)} test/resources/exec/slow.js 100`, { timeout: 10 }); // times out } t.truthy(shell.error()); }); diff --git a/test/find.js b/test/find.js index a37dcd314..2f9e0aa6c 100644 --- a/test/find.js +++ b/test/find.js @@ -24,7 +24,7 @@ test('no args', t => { // test('current path', t => { - shell.cd('resources/find'); + shell.cd('test/resources/find'); const result = shell.find('.'); t.falsy(shell.error()); t.is(result.code, 0); @@ -35,34 +35,34 @@ test('current path', t => { }); test('simple path', t => { - const result = shell.find('resources/find'); + const result = shell.find('test/resources/find'); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/find/.hidden') > -1); - t.truthy(result.indexOf('resources/find/dir1/dir11/a_dir11') > -1); + t.truthy(result.indexOf('test/resources/find/.hidden') > -1); + t.truthy(result.indexOf('test/resources/find/dir1/dir11/a_dir11') > -1); t.is(result.length, 11); }); test('multiple paths - comma', t => { - const result = shell.find('resources/find/dir1', 'resources/find/dir2'); + const result = shell.find('test/resources/find/dir1', 'test/resources/find/dir2'); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/find/dir1/dir11/a_dir11') > -1); - t.truthy(result.indexOf('resources/find/dir2/a_dir1') > -1); + t.truthy(result.indexOf('test/resources/find/dir1/dir11/a_dir11') > -1); + t.truthy(result.indexOf('test/resources/find/dir2/a_dir1') > -1); t.is(result.length, 6); }); test('multiple paths - array', t => { - const result = shell.find(['resources/find/dir1', 'resources/find/dir2']); + const result = shell.find(['test/resources/find/dir1', 'test/resources/find/dir2']); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/find/dir1/dir11/a_dir11') > -1); - t.truthy(result.indexOf('resources/find/dir2/a_dir1') > -1); + t.truthy(result.indexOf('test/resources/find/dir1/dir11/a_dir11') > -1); + t.truthy(result.indexOf('test/resources/find/dir2/a_dir1') > -1); t.is(result.length, 6); }); test('nonexistent path', t => { - const result = shell.find('resources/find/nonexistent'); - t.is(shell.error(), 'find: no such file or directory: resources/find/nonexistent'); + const result = shell.find('test/resources/find/nonexistent'); + t.is(shell.error(), 'find: no such file or directory: test/resources/find/nonexistent'); t.is(result.code, 1); }); diff --git a/test/global.js b/test/global.js index 3f339e2b6..b11251c3f 100644 --- a/test/global.js +++ b/test/global.js @@ -26,14 +26,14 @@ test('env is exported', t => { }); test('cat', t => { - const result = cat('resources/cat/file1'); + const result = cat('test/resources/cat/file1'); t.falsy(error()); t.is(result.code, 0); t.is(result.toString(), 'test1\n'); }); test('rm', t => { - cp('-f', 'resources/file1', `${t.context.tmp}/file1`); + cp('-f', 'test/resources/file1', `${t.context.tmp}/file1`); t.truthy(fs.existsSync(`${t.context.tmp}/file1`)); const result = rm(`${t.context.tmp}/file1`); t.falsy(error()); diff --git a/test/grep.js b/test/grep.js index 3d9dc2335..2fc62f50e 100644 --- a/test/grep.js +++ b/test/grep.js @@ -8,7 +8,7 @@ import utils from './utils/utils'; test.beforeEach(t => { t.context.tmp = utils.getTempDir(); shell.config.resetForTesting(); - shell.cp('-r', 'resources', t.context.tmp); + shell.cp('-r', 'test/resources', t.context.tmp); }); test.afterEach.always(t => { @@ -54,82 +54,82 @@ test('if at least one file is missing, this should be an error', t => { // test('basic', t => { - const result = shell.grep('line', 'resources/a.txt'); + const result = shell.grep('line', 'test/resources/a.txt'); t.falsy(shell.error()); t.is(result.split('\n').length - 1, 4); }); test('-v option', t => { - const result = shell.grep('-v', 'line', 'resources/a.txt'); + const result = shell.grep('-v', 'line', 'test/resources/a.txt'); t.falsy(shell.error()); t.is(result.split('\n').length - 1, 8); }); test('matches one line', t => { - const result = shell.grep('line one', 'resources/a.txt'); + const result = shell.grep('line one', 'test/resources/a.txt'); t.falsy(shell.error()); t.is(result.toString(), 'This is line one\n'); }); test('multiple files', t => { - const result = shell.grep(/test/, 'resources/file1.txt', - 'resources/file2.txt'); + const result = shell.grep(/test/, 'test/resources/file1.txt', + 'test/resources/file2.txt'); t.falsy(shell.error()); t.is(result.toString(), 'test1\ntest2\n'); }); test('multiple files, array syntax', t => { - const result = shell.grep(/test/, ['resources/file1.txt', - 'resources/file2.txt']); + const result = shell.grep(/test/, ['test/resources/file1.txt', + 'test/resources/file2.txt']); t.falsy(shell.error()); t.is(result.toString(), 'test1\ntest2\n'); }); test('multiple files, glob syntax, * for file name', t => { - const result = shell.grep(/test/, 'resources/file*.txt'); + const result = shell.grep(/test/, 'test/resources/file*.txt'); t.falsy(shell.error()); t.truthy(result.toString(), 'test1\ntest2\n'); }); test('multiple files, glob syntax, * for directory name', t => { - const result = shell.grep(/test/, 'r*/file*.txt'); + const result = shell.grep(/test/, 'test/r*/file*.txt'); t.falsy(shell.error()); t.is(result.toString(), 'test1\ntest2\n'); }); test('multiple files, double-star glob', t => { - const result = shell.grep(/test/, 'resources/**/file*.js'); + const result = shell.grep(/test/, 'test/resources/**/file*.js'); t.falsy(shell.error()); t.is(result.toString(), 'test\ntest\ntest\ntest\n'); }); test('one file, * in regex', t => { - const result = shell.grep(/alpha*beta/, 'resources/grep/file'); + const result = shell.grep(/alpha*beta/, 'test/resources/grep/file'); t.falsy(shell.error()); t.is(result.toString(), 'alphaaaaaaabeta\nalphbeta\n'); }); test('one file, * in string-regex', t => { - const result = shell.grep('alpha*beta', 'resources/grep/file'); + const result = shell.grep('alpha*beta', 'test/resources/grep/file'); t.falsy(shell.error()); t.is(result.toString(), 'alphaaaaaaabeta\nalphbeta\n'); }); test('one file, * in regex, make sure * is not globbed', t => { - const result = shell.grep(/l*\.js/, 'resources/grep/file'); + const result = shell.grep(/l*\.js/, 'test/resources/grep/file'); t.falsy(shell.error()); t.is(result.toString(), 'this line ends in.js\nlllllllllllllllll.js\n'); }); test('one file, * in string-regex, make sure * is not globbed', t => { - const result = shell.grep('l*\\.js', 'resources/grep/file'); + const result = shell.grep('l*\\.js', 'test/resources/grep/file'); t.falsy(shell.error()); t.is(result.toString(), 'this line ends in.js\nlllllllllllllllll.js\n'); }); test('-l option', t => { - const result = shell.grep('-l', 'test1', 'resources/file1', 'resources/file2', - 'resources/file1.txt'); + const result = shell.grep('-l', 'test1', 'test/resources/file1', 'test/resources/file2', + 'test/resources/file1.txt'); t.falsy(shell.error()); t.truthy(result.match(/file1(\n|$)/)); t.truthy(result.match(/file1.txt/)); diff --git a/test/head.js b/test/head.js index 0f976e543..9d85aca6a 100644 --- a/test/head.js +++ b/test/head.js @@ -25,11 +25,11 @@ test('file does not exist', t => { }); test('directory', t => { - t.truthy(fs.statSync('resources/').isDirectory()); // sanity check - const result = shell.head('resources/'); + t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + const result = shell.head('test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, "head: error reading 'resources/': Is a directory"); + t.is(result.stderr, "head: error reading 'test/resources/': Is a directory"); }); // @@ -46,15 +46,15 @@ const topOfFile2 = ['file2 1', 'file2 2', 'file2 3', 'file2 4', 'file2 5', 'file2 16', 'file2 17', 'file2 18', 'file2 19', 'file2 20']; test('simple', t => { - const result = shell.head('resources/head/file1.txt'); + const result = shell.head('test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), topOfFile1.slice(0, 10).join('\n') + '\n'); }); test('multiple files', t => { - const result = shell.head('resources/head/file2.txt', - 'resources/head/file1.txt'); + const result = shell.head('test/resources/head/file2.txt', + 'test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), topOfFile2 @@ -64,8 +64,8 @@ test('multiple files', t => { }); test('multiple files, array syntax', t => { - const result = shell.head(['resources/head/file2.txt', - 'resources/head/file1.txt']); + const result = shell.head(['test/resources/head/file2.txt', + 'test/resources/head/file1.txt']); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), topOfFile2 @@ -75,22 +75,22 @@ test('multiple files, array syntax', t => { }); test('reading more lines than are in the file (no trailing newline)', t => { - const result = shell.head('resources/file2', 'resources/file1'); + const result = shell.head('test/resources/file2', 'test/resources/file1'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), 'test2\ntest1'); // these files only have one line (no \n) }); test('reading more lines than are in the file (with trailing newline)', t => { - const result = shell.head('resources/head/shortfile2', - 'resources/head/shortfile1'); + const result = shell.head('test/resources/head/shortfile2', + 'test/resources/head/shortfile1'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), 'short2\nshort1\n'); // these files only have one line (with \n) }); test('Globbed file', t => { - const result = shell.head('resources/head/file?.txt'); + const result = shell.head('test/resources/head/file?.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), topOfFile1 @@ -100,8 +100,8 @@ test('Globbed file', t => { }); test('With `\'-n\' ` option', t => { - const result = shell.head('-n', 4, 'resources/head/file2.txt', - 'resources/head/file1.txt'); + const result = shell.head('-n', 4, 'test/resources/head/file2.txt', + 'test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), topOfFile2 @@ -111,8 +111,8 @@ test('With `\'-n\' ` option', t => { }); test('With `{\'-n\': }` option', t => { - const result = shell.head({ '-n': 4 }, 'resources/head/file2.txt', - 'resources/head/file1.txt'); + const result = shell.head({ '-n': 4 }, 'test/resources/head/file2.txt', + 'test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), topOfFile2 @@ -122,14 +122,14 @@ test('With `{\'-n\': }` option', t => { }); test('negative values (-num) are the same as (numLines - num)', t => { - const result = shell.head('-n', -46, 'resources/head/file1.txt'); + const result = shell.head('-n', -46, 'test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), 'file1 1\nfile1 2\nfile1 3\nfile1 4\n'); }); test('right-hand side of a pipe', t => { - const result = shell.cat('resources/head/file1.txt').head(); + const result = shell.cat('test/resources/head/file1.txt').head(); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), topOfFile1.slice(0, 10).join('\n') + '\n'); diff --git a/test/ln.js b/test/ln.js index 836be4e48..b16820584 100644 --- a/test/ln.js +++ b/test/ln.js @@ -11,7 +11,7 @@ const CWD = process.cwd(); test.beforeEach(t => { t.context.tmp = utils.getTempDir(); shell.config.resetForTesting(); - shell.cp('-r', 'resources', t.context.tmp); + shell.cp('-r', 'test/resources', t.context.tmp); process.chdir(CWD); }); diff --git a/test/ls.js b/test/ls.js index d2c09a23c..2131aff3b 100644 --- a/test/ls.js +++ b/test/ls.js @@ -48,7 +48,7 @@ test('root directory', t => { }); test('no args provides the correct result', t => { - shell.cd('resources/ls'); + shell.cd('test/resources/ls'); const result = shell.ls(); t.falsy(shell.error()); t.is(result.code, 0); @@ -62,7 +62,7 @@ test('no args provides the correct result', t => { }); test('simple arg', t => { - const result = shell.ls('resources/ls'); + const result = shell.ls('test/resources/ls'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.indexOf('file1') > -1); @@ -75,7 +75,7 @@ test('simple arg', t => { }); test('simple arg, with a trailing slash', t => { - const result = shell.ls('resources/ls/'); + const result = shell.ls('test/resources/ls/'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.indexOf('file1') > -1); @@ -88,7 +88,7 @@ test('simple arg, with a trailing slash', t => { }); test('no args, -A option', t => { - shell.cd('resources/ls'); + shell.cd('test/resources/ls'); const result = shell.ls('-A'); t.falsy(shell.error()); t.is(result.code, 0); @@ -104,7 +104,7 @@ test('no args, -A option', t => { }); test('no args, deprecated -a option', t => { - shell.cd('resources/ls'); + shell.cd('test/resources/ls'); const result = shell.ls('-a'); // (deprecated) backwards compatibility test t.falsy(shell.error()); t.is(result.code, 0); @@ -120,148 +120,148 @@ test('no args, deprecated -a option', t => { }); test('wildcard, very simple', t => { - const result = shell.ls('resources/cat/*'); + const result = shell.ls('test/resources/cat/*'); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/cat/file1') > -1); - t.truthy(result.indexOf('resources/cat/file2') > -1); + t.truthy(result.indexOf('test/resources/cat/file1') > -1); + t.truthy(result.indexOf('test/resources/cat/file2') > -1); t.is(result.length, 2); }); test('wildcard, simple', t => { - const result = shell.ls('resources/ls/*'); + const result = shell.ls('test/resources/ls/*'); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/ls/file1') > -1); - t.truthy(result.indexOf('resources/ls/file2') > -1); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); - t.truthy(result.indexOf('resources/ls/file2.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1') > -1); + t.truthy(result.indexOf('test/resources/ls/file2') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2.js') > -1); t.truthy( - result.indexOf('resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 + result.indexOf('test/resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 ); - t.is(result.indexOf('resources/ls/a_dir'), -1); // this shouldn't be there + t.is(result.indexOf('test/resources/ls/a_dir'), -1); // this shouldn't be there t.truthy(result.indexOf('nada') > -1); t.truthy(result.indexOf('b_dir') > -1); t.is(result.length, 7); }); test('wildcard, simple, with -d', t => { - const result = shell.ls('-d', 'resources/ls/*'); + const result = shell.ls('-d', 'test/resources/ls/*'); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/ls/file1') > -1); - t.truthy(result.indexOf('resources/ls/file2') > -1); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); - t.truthy(result.indexOf('resources/ls/file2.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1') > -1); + t.truthy(result.indexOf('test/resources/ls/file2') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2.js') > -1); t.truthy( - result.indexOf('resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 + result.indexOf('test/resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 ); - t.truthy(result.indexOf('resources/ls/a_dir') > -1); + t.truthy(result.indexOf('test/resources/ls/a_dir') > -1); t.is(result.length, 6); }); test('wildcard, hidden only', t => { - const result = shell.ls('-d', 'resources/ls/.*'); + const result = shell.ls('-d', 'test/resources/ls/.*'); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/ls/.hidden_file') > -1); - t.truthy(result.indexOf('resources/ls/.hidden_dir') > -1); + t.truthy(result.indexOf('test/resources/ls/.hidden_file') > -1); + t.truthy(result.indexOf('test/resources/ls/.hidden_dir') > -1); t.is(result.length, 2); }); test('wildcard, mid-file', t => { - const result = shell.ls('resources/ls/f*le*'); + const result = shell.ls('test/resources/ls/f*le*'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.length, 5); - t.truthy(result.indexOf('resources/ls/file1') > -1); - t.truthy(result.indexOf('resources/ls/file2') > -1); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); - t.truthy(result.indexOf('resources/ls/file2.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1') > -1); + t.truthy(result.indexOf('test/resources/ls/file2') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2.js') > -1); t.truthy( - result.indexOf('resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 + result.indexOf('test/resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 ); }); test('wildcard, mid-file with dot (should escape dot for regex)', t => { - const result = shell.ls('resources/ls/f*le*.js'); + const result = shell.ls('test/resources/ls/f*le*.js'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.length, 2); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); - t.truthy(result.indexOf('resources/ls/file2.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2.js') > -1); }); test('one file that exists, one that doesn\'t', t => { - const result = shell.ls('resources/ls/file1.js', 'resources/ls/thisdoesntexist'); + const result = shell.ls('test/resources/ls/file1.js', 'test/resources/ls/thisdoesntexist'); t.truthy(shell.error()); t.is(result.code, 2); t.is(result.length, 1); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); }); test('one file that exists, one that doesn\'t (other order)', t => { - const result = shell.ls('resources/ls/thisdoesntexist', 'resources/ls/file1.js'); + const result = shell.ls('test/resources/ls/thisdoesntexist', 'test/resources/ls/file1.js'); t.truthy(shell.error()); t.is(result.code, 2); t.is(result.length, 1); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); }); test('wildcard, should not do partial matches', t => { - const result = shell.ls('resources/ls/*.j'); // shouldn't get .js + const result = shell.ls('test/resources/ls/*.j'); // shouldn't get .js t.truthy(shell.error()); t.is(result.code, 2); t.is(result.length, 0); }); test('wildcard, all files with extension', t => { - const result = shell.ls('resources/ls/*.*'); + const result = shell.ls('test/resources/ls/*.*'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.length, 3); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); - t.truthy(result.indexOf('resources/ls/file2.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2.js') > -1); t.truthy( - result.indexOf('resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 + result.indexOf('test/resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 ); }); test('wildcard, with additional path', t => { - const result = shell.ls('resources/ls/f*le*.js', 'resources/ls/a_dir'); + const result = shell.ls('test/resources/ls/f*le*.js', 'test/resources/ls/a_dir'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.length, 4); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); - t.truthy(result.indexOf('resources/ls/file2.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2.js') > -1); t.truthy(result.indexOf('b_dir') > -1); // no wildcard == no path prefix t.truthy(result.indexOf('nada') > -1); // no wildcard == no path prefix }); test('wildcard for both paths', t => { - const result = shell.ls('resources/ls/f*le*.js', 'resources/ls/a_dir/*'); + const result = shell.ls('test/resources/ls/f*le*.js', 'test/resources/ls/a_dir/*'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.length, 4); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); - t.truthy(result.indexOf('resources/ls/file2.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2.js') > -1); t.truthy(result.indexOf('z') > -1); - t.truthy(result.indexOf('resources/ls/a_dir/nada') > -1); + t.truthy(result.indexOf('test/resources/ls/a_dir/nada') > -1); }); test('wildcard for both paths, array', t => { - const result = shell.ls(['resources/ls/f*le*.js', 'resources/ls/a_dir/*']); + const result = shell.ls(['test/resources/ls/f*le*.js', 'test/resources/ls/a_dir/*']); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.length, 4); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); - t.truthy(result.indexOf('resources/ls/file2.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2.js') > -1); t.truthy(result.indexOf('z') > -1); - t.truthy(result.indexOf('resources/ls/a_dir/nada') > -1); + t.truthy(result.indexOf('test/resources/ls/a_dir/nada') > -1); }); test('recursive, no path', t => { - shell.cd('resources/ls'); + shell.cd('test/resources/ls'); const result = shell.ls('-R'); t.falsy(shell.error()); t.is(result.code, 0); @@ -272,7 +272,7 @@ test('recursive, no path', t => { }); test('recursive, path given', t => { - const result = shell.ls('-R', 'resources/ls'); + const result = shell.ls('-R', 'test/resources/ls'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.indexOf('a_dir') > -1); @@ -282,7 +282,7 @@ test('recursive, path given', t => { }); test('-RA flag, path given', t => { - const result = shell.ls('-RA', 'resources/ls'); + const result = shell.ls('-RA', 'test/resources/ls'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.indexOf('a_dir') > -1); @@ -293,7 +293,7 @@ test('-RA flag, path given', t => { }); test('-RA flag, symlinks are not followed', t => { - const result = shell.ls('-RA', 'resources/rm'); + const result = shell.ls('-RA', 'test/resources/rm'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.indexOf('a_dir') > -1); @@ -306,7 +306,7 @@ test('-RA flag, symlinks are not followed', t => { test('-RAL flag, follows symlinks', t => { utils.skipOnWin(t, () => { - const result = shell.ls('-RAL', 'resources/rm'); + const result = shell.ls('-RAL', 'test/resources/rm'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.indexOf('a_dir') > -1); @@ -320,7 +320,7 @@ test('-RAL flag, follows symlinks', t => { test('-L flag, path is symlink', t => { utils.skipOnWin(t, () => { - const result = shell.ls('-L', 'resources/rm/link_to_a_dir'); + const result = shell.ls('-L', 'test/resources/rm/link_to_a_dir'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.indexOf('a_file') > -1); @@ -329,52 +329,52 @@ test('-L flag, path is symlink', t => { }); test('-Rd works like -d', t => { - const result = shell.ls('-Rd', 'resources/ls'); + const result = shell.ls('-Rd', 'test/resources/ls'); t.falsy(shell.error()); t.is(result.length, 1); }); test('directory option, single arg', t => { - const result = shell.ls('-d', 'resources/ls'); + const result = shell.ls('-d', 'test/resources/ls'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.length, 1); }); test('directory option, single arg with trailing \'/\'', t => { - const result = shell.ls('-d', 'resources/ls/'); + const result = shell.ls('-d', 'test/resources/ls/'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.length, 1); }); test('directory option, multiple args', t => { - const result = shell.ls('-d', 'resources/ls/a_dir', 'resources/ls/file1'); + const result = shell.ls('-d', 'test/resources/ls/a_dir', 'test/resources/ls/file1'); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/ls/a_dir') > -1); - t.truthy(result.indexOf('resources/ls/file1') > -1); + t.truthy(result.indexOf('test/resources/ls/a_dir') > -1); + t.truthy(result.indexOf('test/resources/ls/file1') > -1); t.is(result.length, 2); }); test('directory option, globbed arg', t => { - const result = shell.ls('-d', 'resources/ls/*'); + const result = shell.ls('-d', 'test/resources/ls/*'); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/ls/a_dir') > -1); - t.truthy(result.indexOf('resources/ls/file1') > -1); - t.truthy(result.indexOf('resources/ls/file1.js') > -1); - t.truthy(result.indexOf('resources/ls/file2') > -1); - t.truthy(result.indexOf('resources/ls/file2.js') > -1); - t.truthy(result.indexOf('resources/ls/file2') > -1); + t.truthy(result.indexOf('test/resources/ls/a_dir') > -1); + t.truthy(result.indexOf('test/resources/ls/file1') > -1); + t.truthy(result.indexOf('test/resources/ls/file1.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2') > -1); + t.truthy(result.indexOf('test/resources/ls/file2.js') > -1); + t.truthy(result.indexOf('test/resources/ls/file2') > -1); t.truthy( - result.indexOf('resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 + result.indexOf('test/resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1 ); t.is(result.length, 6); }); test('long option, single file', t => { - let result = shell.ls('-l', 'resources/ls/file1'); + let result = shell.ls('-l', 'test/resources/ls/file1'); t.is(result.length, 1); result = result[0]; t.falsy(shell.error()); @@ -393,7 +393,7 @@ test('long option, single file', t => { }); test('long option, glob files', t => { - let result = shell.ls('-l', 'resources/ls/f*le1'); + let result = shell.ls('-l', 'test/resources/ls/f*le1'); t.is(result.length, 1); result = result[0]; t.falsy(shell.error()); @@ -412,7 +412,7 @@ test('long option, glob files', t => { }); test('long option, directory', t => { - let result = shell.ls('-l', 'resources/ls'); + let result = shell.ls('-l', 'test/resources/ls'); t.falsy(shell.error()); t.is(result.code, 0); const idx = result.map(r => r.name).indexOf('file1'); @@ -434,7 +434,7 @@ test('long option, directory', t => { }); test('long option, directory, recursive (and windows converts slashes)', t => { - let result = shell.ls('-lR', 'resources/ls/'); + let result = shell.ls('-lR', 'test/resources/ls/'); t.falsy(shell.error()); t.is(result.code, 0); const idx = result.map(r => r.name).indexOf('a_dir/b_dir'); @@ -442,7 +442,7 @@ test('long option, directory, recursive (and windows converts slashes)', t => { t.truthy(idx >= 0); result = result[idx]; t.is(result.name, result.name); - t.truthy(fs.statSync('resources/ls/a_dir/b_dir').isDirectory()); + t.truthy(fs.statSync('test/resources/ls/a_dir/b_dir').isDirectory()); t.is(typeof result.nlink, 'number'); // This can vary between the local machine and travis t.is(typeof result.size, 'number'); // This can vary between different file systems t.truthy(result.mode); // check that these keys exist @@ -457,15 +457,15 @@ test('long option, directory, recursive (and windows converts slashes)', t => { }); test('still lists broken links', t => { - const result = shell.ls('resources/badlink'); + const result = shell.ls('test/resources/badlink'); t.falsy(shell.error()); t.is(result.code, 0); - t.truthy(result.indexOf('resources/badlink') > -1); + t.truthy(result.indexOf('test/resources/badlink') > -1); t.is(result.length, 1); }); test('Test new ShellString-like attributes', t => { - const result = shell.ls('resources/ls'); + const result = shell.ls('test/resources/ls'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.stdout.indexOf('file1') > -1); @@ -496,13 +496,13 @@ test('No trailing newline for ls() on empty directories', t => { test('Check stderr field', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.ls('resources/ls/file1', '/asdfasdf'); + const result = shell.ls('test/resources/ls/file1', '/asdfasdf'); t.truthy(shell.error()); t.is('ls: no such file or directory: /asdfasdf', result.stderr); }); test('non-normalized paths are still ok with -R', t => { - const result = shell.ls('-R', 'resources/./ls/../ls'); + const result = shell.ls('-R', 'test/resources/./ls/../ls'); t.falsy(shell.error()); t.is(result.code, 0); t.truthy(result.indexOf('a_dir') > -1); diff --git a/test/mkdir.js b/test/mkdir.js index f49089a35..3827c2d38 100644 --- a/test/mkdir.js +++ b/test/mkdir.js @@ -37,12 +37,12 @@ test('dir already exists', t => { }); test('Can\'t overwrite a broken link', t => { - const mtime = fs.lstatSync('resources/badlink').mtime.toString(); - const result = shell.mkdir('resources/badlink'); + const mtime = fs.lstatSync('test/resources/badlink').mtime.toString(); + const result = shell.mkdir('test/resources/badlink'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, 'mkdir: path already exists: resources/badlink'); - t.is(fs.lstatSync('resources/badlink').mtime.toString(), mtime); // didn't mess with file + t.is(result.stderr, 'mkdir: path already exists: test/resources/badlink'); + t.is(fs.lstatSync('test/resources/badlink').mtime.toString(), mtime); // didn't mess with file }); test('root path does not exist', t => { @@ -56,31 +56,31 @@ test('root path does not exist', t => { }); test('try to overwrite file', t => { - t.truthy(fs.statSync('resources/file1').isFile()); - const result = shell.mkdir('resources/file1'); + t.truthy(fs.statSync('test/resources/file1').isFile()); + const result = shell.mkdir('test/resources/file1'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, 'mkdir: path already exists: resources/file1'); - t.truthy(fs.statSync('resources/file1').isFile()); + t.is(result.stderr, 'mkdir: path already exists: test/resources/file1'); + t.truthy(fs.statSync('test/resources/file1').isFile()); }); test('try to overwrite file, with -p', t => { - t.truthy(fs.statSync('resources/file1').isFile()); - const result = shell.mkdir('-p', 'resources/file1'); + t.truthy(fs.statSync('test/resources/file1').isFile()); + const result = shell.mkdir('-p', 'test/resources/file1'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, 'mkdir: cannot create directory resources/file1: File exists'); - t.truthy(fs.statSync('resources/file1').isFile()); + t.is(result.stderr, 'mkdir: cannot create directory test/resources/file1: File exists'); + t.truthy(fs.statSync('test/resources/file1').isFile()); }); test('try to make a subdirectory of a file', t => { - t.truthy(fs.statSync('resources/file1').isFile()); - const result = shell.mkdir('resources/file1/subdir'); + t.truthy(fs.statSync('test/resources/file1').isFile()); + const result = shell.mkdir('test/resources/file1/subdir'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, 'mkdir: cannot create directory resources/file1/subdir: Not a directory'); - t.truthy(fs.statSync('resources/file1').isFile()); - t.falsy(fs.existsSync('resources/file1/subdir')); + t.is(result.stderr, 'mkdir: cannot create directory test/resources/file1/subdir: Not a directory'); + t.truthy(fs.statSync('test/resources/file1').isFile()); + t.falsy(fs.existsSync('test/resources/file1/subdir')); }); test('Check for invalid permissions', t => { diff --git a/test/mv.js b/test/mv.js index 32bc80ef8..eb68bd708 100644 --- a/test/mv.js +++ b/test/mv.js @@ -11,7 +11,7 @@ const numLines = utils.numLines; test.beforeEach(t => { t.context.tmp = utils.getTempDir(); shell.config.resetForTesting(); - shell.cp('-r', 'resources', t.context.tmp); + shell.cp('-r', 'test/resources', t.context.tmp); shell.cd(t.context.tmp); }); diff --git a/test/pipe.js b/test/pipe.js index cc71e0cf0..ab75d944a 100644 --- a/test/pipe.js +++ b/test/pipe.js @@ -10,7 +10,7 @@ shell.config.silent = true; test('commands like `rm` cannot be on the right side of pipes', t => { t.is(shell.ls('.').rm, undefined); - t.is(shell.cat('resources/file1.txt').rm, undefined); + t.is(shell.cat('test/resources/file1.txt').rm, undefined); }); // @@ -19,33 +19,33 @@ test('commands like `rm` cannot be on the right side of pipes', t => { test('piping to cat() should return roughly the same thing', t => { t.is( - shell.cat('resources/file1.txt').cat().toString(), - shell.cat('resources/file1.txt').toString() + shell.cat('test/resources/file1.txt').cat().toString(), + shell.cat('test/resources/file1.txt').toString() ); }); test('piping ls() into cat() converts to a string-like object', t => { - t.is(shell.ls('resources/').cat().toString(), shell.ls('resources/').stdout); + t.is(shell.ls('test/resources/').cat().toString(), shell.ls('test/resources/').stdout); }); test('grep works in a pipe', t => { - const result = shell.ls('resources/').grep('file1'); + const result = shell.ls('test/resources/').grep('file1'); t.is(result.toString(), 'file1\nfile1.js\nfile1.txt\n'); }); test('multiple pipes work', t => { - const result = shell.ls('resources/').cat().grep('file1'); + const result = shell.ls('test/resources/').cat().grep('file1'); t.is(result.toString(), 'file1\nfile1.js\nfile1.txt\n'); }); test('Equivalent to a simple grep() test case', t => { - const result = shell.cat('resources/grep/file').grep(/alpha*beta/); + const result = shell.cat('test/resources/grep/file').grep(/alpha*beta/); t.falsy(shell.error()); t.is(result.toString(), 'alphaaaaaaabeta\nalphbeta\n'); }); test('Equivalent to a simple sed() test case', t => { - const result = shell.cat('resources/grep/file').sed(/l*\.js/, ''); + const result = shell.cat('test/resources/grep/file').sed(/l*\.js/, ''); t.falsy(shell.error()); t.is( result.toString(), @@ -54,19 +54,19 @@ test('Equivalent to a simple sed() test case', t => { }); test('Sort a file by frequency of each line', t => { - const result = shell.sort('resources/uniq/pipe').uniq('-c').sort('-n'); + const result = shell.sort('test/resources/uniq/pipe').uniq('-c').sort('-n'); t.falsy(shell.error()); - t.is(result.toString(), shell.cat('resources/uniq/pipeSorted').toString()); + t.is(result.toString(), shell.cat('test/resources/uniq/pipeSorted').toString()); }); test('Synchronous exec', t => { - const result = shell.cat('resources/grep/file').exec('shx grep "alpha*beta"'); + const result = shell.cat('test/resources/grep/file').exec('shx grep "alpha*beta"'); t.falsy(shell.error()); t.is(result.toString(), 'alphaaaaaaabeta\nalphbeta\n'); }); test.cb('Asynchronous exec', t => { - shell.cat('resources/grep/file').exec('shx grep "alpha*beta"', (code, stdout) => { + shell.cat('test/resources/grep/file').exec('shx grep "alpha*beta"', (code, stdout) => { t.is(code, 0); t.is(stdout, 'alphaaaaaaabeta\nalphbeta\n'); t.end(); diff --git a/test/plugin.js b/test/plugin.js index 7b7594bfd..e8a2bbc4f 100644 --- a/test/plugin.js +++ b/test/plugin.js @@ -95,9 +95,9 @@ test('The command parses options', t => { }); test('The command supports globbing by default', t => { - shell.foo('-f', 're*u?ces'); + shell.foo('-f', 'test/re*u?ces'); t.is(data, 12); - t.is(fname, 'resources'); + t.is(fname, 'test/resources'); }); test('Plugins are also compatible with shelljs/global', t => { diff --git a/test/popd.js b/test/popd.js index 0ac1447c8..0e83a7cfa 100644 --- a/test/popd.js +++ b/test/popd.js @@ -26,7 +26,7 @@ test.after.always(() => { // test('basic usage', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); const trail = shell.popd(); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); @@ -34,33 +34,33 @@ test('basic usage', t => { }); test('two directories on the stack', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); const trail = shell.popd(); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, ]); }); test('three directories on the stack', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('b'); shell.pushd('c'); const trail = shell.popd(); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, ]); }); test('Valid by index', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); const trail = shell.popd('+0'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); @@ -68,23 +68,23 @@ test('Valid by index', t => { }); test('Using +1 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); const trail = shell.popd('+1'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); - t.deepEqual(trail, [path.resolve(rootDir, 'resources/pushd')]); + t.deepEqual(trail, [path.resolve(rootDir, 'test/resources/pushd')]); }); test('Using -0 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); const trail = shell.popd('-0'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); - t.deepEqual(trail, [path.resolve(rootDir, 'resources/pushd')]); + t.deepEqual(trail, [path.resolve(rootDir, 'test/resources/pushd')]); }); test('Using -1 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); const trail = shell.popd('-1'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); @@ -92,11 +92,11 @@ test('Using -1 option', t => { }); test('Using -n option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); const trail = shell.popd('-n'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); - t.deepEqual(trail, [path.resolve(rootDir, 'resources/pushd')]); + t.deepEqual(trail, [path.resolve(rootDir, 'test/resources/pushd')]); }); test('Popping an empty stack', t => { @@ -105,11 +105,11 @@ test('Popping an empty stack', t => { }); test('Test that rootDir is not stored', t => { - shell.cd('resources/pushd'); + shell.cd('test/resources/pushd'); shell.pushd('b'); const trail = shell.popd(); t.falsy(shell.error()); - t.is(trail[0], path.resolve(rootDir, 'resources/pushd')); + t.is(trail[0], path.resolve(rootDir, 'test/resources/pushd')); t.is(process.cwd(), trail[0]); shell.popd(); // no more in the stack t.truthy(shell.error()); diff --git a/test/pushd.js b/test/pushd.js index 68d266849..9ca0f76b0 100644 --- a/test/pushd.js +++ b/test/pushd.js @@ -25,59 +25,59 @@ test.after.always(() => { // test('Push valid directories', t => { - const trail = shell.pushd('resources/pushd'); + const trail = shell.pushd('test/resources/pushd'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, ]); }); test('Two directories', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); const trail = shell.pushd('a'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, ]); }); test('Three directories', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); const trail = shell.pushd('../b'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, ]); }); test('Four directories', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); const trail = shell.pushd('c'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/b/c'), - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, ]); }); test('Push stuff around with positive indices', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -85,16 +85,16 @@ test('Push stuff around with positive indices', t => { t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/b/c'), - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, ]); }); test('+1 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -102,16 +102,16 @@ test('+1 option', t => { t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, - path.resolve(rootDir, 'resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), ]); }); test('+2 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -119,16 +119,16 @@ test('+2 option', t => { t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, - path.resolve(rootDir, 'resources/pushd/b/c'), - path.resolve(rootDir, 'resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b'), ]); }); test('+3 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -136,16 +136,16 @@ test('+3 option', t => { t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, - path.resolve(rootDir, 'resources/pushd/b/c'), - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), ]); }); test('+4 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -154,15 +154,15 @@ test('+4 option', t => { t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ rootDir, - path.resolve(rootDir, 'resources/pushd/b/c'), - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), ]); }); test('Push stuff around with negative indices', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -171,15 +171,15 @@ test('Push stuff around with negative indices', t => { t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ rootDir, - path.resolve(rootDir, 'resources/pushd/b/c'), - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), ]); }); test('-1 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -187,16 +187,16 @@ test('-1 option', t => { t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, - path.resolve(rootDir, 'resources/pushd/b/c'), - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), ]); }); test('-2 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -204,16 +204,16 @@ test('-2 option', t => { t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, - path.resolve(rootDir, 'resources/pushd/b/c'), - path.resolve(rootDir, 'resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b'), ]); }); test('-3 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -221,16 +221,16 @@ test('-3 option', t => { t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, - path.resolve(rootDir, 'resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), ]); }); test('-4 option', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd('a'); shell.pushd('../b'); shell.pushd('c'); @@ -238,33 +238,33 @@ test('-4 option', t => { t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ - path.resolve(rootDir, 'resources/pushd/b/c'), - path.resolve(rootDir, 'resources/pushd/b'), - path.resolve(rootDir, 'resources/pushd/a'), - path.resolve(rootDir, 'resources/pushd'), + path.resolve(rootDir, 'test/resources/pushd/b/c'), + path.resolve(rootDir, 'test/resources/pushd/b'), + path.resolve(rootDir, 'test/resources/pushd/a'), + path.resolve(rootDir, 'test/resources/pushd'), rootDir, ]); }); test('Push without changing directory or resolving paths', t => { - const trail = shell.pushd('-n', 'resources/pushd'); + const trail = shell.pushd('-n', 'test/resources/pushd'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ rootDir, - 'resources/pushd', + 'test/resources/pushd', ]); }); test('Using the -n option with a non-empty stack', t => { - shell.pushd('-n', 'resources/pushd'); - const trail = shell.pushd('-n', 'resources/pushd/a'); + shell.pushd('-n', 'test/resources/pushd'); + const trail = shell.pushd('-n', 'test/resources/pushd/a'); t.falsy(shell.error()); t.is(process.cwd(), trail[0]); t.deepEqual(trail, [ rootDir, - 'resources/pushd/a', - 'resources/pushd', + 'test/resources/pushd/a', + 'test/resources/pushd', ]); }); @@ -282,17 +282,17 @@ test('Push invalid directory', t => { test( 'Push without args swaps top two directories when stack length is 2', t => { - let trail = shell.pushd('resources/pushd'); + let trail = shell.pushd('test/resources/pushd'); t.falsy(shell.error()); t.is(trail.length, 2); - t.is(path.relative(rootDir, trail[0]), path.join('resources', 'pushd')); + t.is(path.relative(rootDir, trail[0]), path.join('test/resources', 'pushd')); t.is(trail[1], rootDir); t.is(process.cwd(), trail[0]); trail = shell.pushd(); t.falsy(shell.error()); t.is(trail.length, 2); t.is(trail[0], rootDir); - t.is(path.relative(rootDir, trail[1]), path.join('resources', 'pushd')); + t.is(path.relative(rootDir, trail[1]), path.join('test/resources', 'pushd')); t.is(process.cwd(), trail[0]); } ); @@ -300,27 +300,27 @@ test( test( 'Push without args swaps top two directories for larger stacks', t => { - shell.pushd('resources/pushd'); + shell.pushd('test/resources/pushd'); shell.pushd(); - const trail = shell.pushd('resources/pushd/a'); + const trail = shell.pushd('test/resources/pushd/a'); t.falsy(shell.error()); t.is(trail.length, 3); - t.is(path.relative(rootDir, trail[0]), path.join('resources', 'pushd', 'a')); + t.is(path.relative(rootDir, trail[0]), path.join('test/resources', 'pushd', 'a')); t.is(trail[1], rootDir); - t.is(path.relative(rootDir, trail[2]), path.join('resources', 'pushd')); + t.is(path.relative(rootDir, trail[2]), path.join('test/resources', 'pushd')); t.is(process.cwd(), trail[0]); } ); test('Pushing with no args', t => { - shell.pushd('-n', 'resources/pushd'); - shell.pushd('resources/pushd/a'); + shell.pushd('-n', 'test/resources/pushd'); + shell.pushd('test/resources/pushd/a'); const trail = shell.pushd(); t.falsy(shell.error()); t.is(trail.length, 3); t.is(trail[0], rootDir); - t.is(path.relative(rootDir, trail[1]), path.join('resources', 'pushd', 'a')); - t.is(path.relative(rootDir, trail[2]), path.join('resources', 'pushd')); + t.is(path.relative(rootDir, trail[1]), path.join('test/resources', 'pushd', 'a')); + t.is(path.relative(rootDir, trail[2]), path.join('test/resources', 'pushd')); t.is(process.cwd(), trail[0]); }); diff --git a/test/rm.js b/test/rm.js index d3228c7e1..ccd2c6ba6 100644 --- a/test/rm.js +++ b/test/rm.js @@ -9,7 +9,7 @@ import utils from './utils/utils'; test.beforeEach(t => { t.context.tmp = utils.getTempDir(); shell.config.resetForTesting(); - shell.cp('-r', 'resources', t.context.tmp); + shell.cp('-r', 'test/resources', t.context.tmp); }); test.afterEach.always(t => { @@ -50,10 +50,10 @@ test('only an option', t => { }); test('invalid option', t => { - const result = shell.rm('-@', 'resources/file1'); + const result = shell.rm('-@', 'test/resources/file1'); t.truthy(shell.error()); t.is(result.code, 1); - t.truthy(fs.existsSync('resources/file1')); + t.truthy(fs.existsSync('test/resources/file1')); t.is(result.stderr, 'rm: option not recognized: @'); }); diff --git a/test/sed.js b/test/sed.js index c8342c13d..fc65c5412 100644 --- a/test/sed.js +++ b/test/sed.js @@ -8,7 +8,7 @@ import utils from './utils/utils'; test.beforeEach(t => { t.context.tmp = utils.getTempDir(); shell.config.resetForTesting(); - shell.cp('-r', 'resources', t.context.tmp); + shell.cp('-r', 'test/resources', t.context.tmp); }); test.afterEach.always(t => { @@ -99,7 +99,7 @@ test('-i option', t => { }); test('make sure * in regex is not globbed', t => { - const result = shell.sed(/alpha*beta/, 'hello', 'resources/grep/file'); + const result = shell.sed(/alpha*beta/, 'hello', 'test/resources/grep/file'); t.falsy(shell.error()); t.is(result.code, 0); t.is( @@ -109,7 +109,7 @@ test('make sure * in regex is not globbed', t => { }); test('make sure * in string-regex is not globbed', t => { - const result = shell.sed('alpha*beta', 'hello', 'resources/grep/file'); + const result = shell.sed('alpha*beta', 'hello', 'test/resources/grep/file'); t.falsy(shell.error()); t.is(result.code, 0); t.is( @@ -119,7 +119,7 @@ test('make sure * in string-regex is not globbed', t => { }); test('make sure * in regex is not globbed (matches something)', t => { - const result = shell.sed(/l*\.js/, '', 'resources/grep/file'); + const result = shell.sed(/l*\.js/, '', 'test/resources/grep/file'); t.falsy(shell.error()); t.is(result.code, 0); t.is( @@ -129,7 +129,7 @@ test('make sure * in regex is not globbed (matches something)', t => { }); test('make sure * in string-regex is not globbed (matches something)', t => { - const result = shell.sed('l*\\.js', '', 'resources/grep/file'); + const result = shell.sed('l*\\.js', '', 'test/resources/grep/file'); t.falsy(shell.error()); t.is(result.code, 0); t.is( diff --git a/test/set.js b/test/set.js index 957e168d9..55337c1e5 100644 --- a/test/set.js +++ b/test/set.js @@ -9,7 +9,7 @@ const uncaughtErrorExitCode = 1; test.beforeEach(t => { t.context.tmp = utils.getTempDir(); shell.config.resetForTesting(); - shell.cp('-r', 'resources', t.context.tmp); + shell.cp('-r', 'test/resources', t.context.tmp); }); test.afterEach.always(t => { @@ -28,21 +28,21 @@ test('initial values', t => { }); test('default behavior', t => { - const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'../global\'); ls(\'file_doesnt_exist\'); echo(1234);"'); + const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'./global\'); ls(\'file_doesnt_exist\'); echo(1234);"'); t.is(result.code, 0); t.is(result.stdout, '1234\n'); t.is(result.stderr, 'ls: no such file or directory: file_doesnt_exist\n'); }); test('set -e', t => { - const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'../global\'); set(\'-e\'); ls(\'file_doesnt_exist\'); echo(1234);"'); + const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'./global\'); set(\'-e\'); ls(\'file_doesnt_exist\'); echo(1234);"'); t.is(result.code, uncaughtErrorExitCode); t.is(result.stdout, ''); t.truthy(result.stderr.indexOf('Error: ls: no such file or directory: file_doesnt_exist') >= 0); }); test('set -v', t => { - const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'../global\'); set(\'-v\'); ls(\'file_doesnt_exist\'); echo(1234);"'); + const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'./global\'); set(\'-v\'); ls(\'file_doesnt_exist\'); echo(1234);"'); t.is(result.code, 0); t.is(result.stdout, '1234\n'); t.is( @@ -52,7 +52,7 @@ test('set -v', t => { }); test('set -ev', t => { - const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'../global\'); set(\'-ev\'); ls(\'file_doesnt_exist\'); echo(1234);"'); + const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'./global\'); set(\'-ev\'); ls(\'file_doesnt_exist\'); echo(1234);"'); t.is(result.code, uncaughtErrorExitCode); t.is(result.stdout, ''); t.truthy(result.stderr.indexOf('Error: ls: no such file or directory: file_doesnt_exist') >= 0); @@ -61,7 +61,7 @@ test('set -ev', t => { }); test('set -e, set +e', t => { - const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'../global\'); set(\'-e\'); set(\'+e\'); ls(\'file_doesnt_exist\'); echo(1234);"'); + const result = shell.exec(JSON.stringify(shell.config.execPath) + ' -e "require(\'./global\'); set(\'-e\'); set(\'+e\'); ls(\'file_doesnt_exist\'); echo(1234);"'); t.is(result.code, 0); t.is(result.stdout, '1234\n'); t.is(result.stderr, 'ls: no such file or directory: file_doesnt_exist\n'); diff --git a/test/sort.js b/test/sort.js index ecba45447..6d28c1e25 100644 --- a/test/sort.js +++ b/test/sort.js @@ -6,7 +6,7 @@ import shell from '..'; shell.config.silent = true; -const doubleSorted = shell.cat('resources/sort/sorted') +const doubleSorted = shell.cat('test/resources/sort/sorted') .trimRight() .split('\n') .reduce((prev, cur) => prev.concat([cur, cur]), []) @@ -31,11 +31,11 @@ test('file does not exist', t => { }); test('directory', t => { - t.truthy(fs.statSync('resources/').isDirectory()); // sanity check - const result = shell.sort('resources/'); + t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + const result = shell.sort('test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, 'sort: read failed: resources/: Is a directory'); + t.is(result.stderr, 'sort: read failed: test/resources/: Is a directory'); }); // @@ -43,52 +43,52 @@ test('directory', t => { // test('simple', t => { - const result = shell.sort('resources/sort/file1'); + const result = shell.sort('test/resources/sort/file1'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/sort/sorted').toString()); + t.is(result.toString(), shell.cat('test/resources/sort/sorted').toString()); }); test('simple #2', t => { - const result = shell.sort('resources/sort/file2'); + const result = shell.sort('test/resources/sort/file2'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/sort/sorted').toString()); + t.is(result.toString(), shell.cat('test/resources/sort/sorted').toString()); }); test('multiple files', t => { - const result = shell.sort('resources/sort/file2', 'resources/sort/file1'); + const result = shell.sort('test/resources/sort/file2', 'test/resources/sort/file1'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), doubleSorted); }); test('multiple files, array syntax', t => { - const result = shell.sort(['resources/sort/file2', 'resources/sort/file1']); + const result = shell.sort(['test/resources/sort/file2', 'test/resources/sort/file1']); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), doubleSorted); }); test('Globbed file', t => { - const result = shell.sort('resources/sort/file?'); + const result = shell.sort('test/resources/sort/file?'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), doubleSorted); }); test('With \'-n\' option', t => { - const result = shell.sort('-n', 'resources/sort/file2'); + const result = shell.sort('-n', 'test/resources/sort/file2'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/sort/sortedDashN').toString()); + t.is(result.toString(), shell.cat('test/resources/sort/sortedDashN').toString()); }); test('With \'-r\' option', t => { - const result = shell.sort('-r', 'resources/sort/file2'); + const result = shell.sort('-r', 'test/resources/sort/file2'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/sort/sorted') + t.is(result.toString(), shell.cat('test/resources/sort/sorted') .trimRight() .split('\n') .reverse() @@ -96,10 +96,10 @@ test('With \'-r\' option', t => { }); test('With \'-rn\' option', t => { - const result = shell.sort('-rn', 'resources/sort/file2'); + const result = shell.sort('-rn', 'test/resources/sort/file2'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/sort/sortedDashN') + t.is(result.toString(), shell.cat('test/resources/sort/sortedDashN') .trimRight() .split('\n') .reverse() diff --git a/test/tail.js b/test/tail.js index 8d3eba261..328fb22ff 100644 --- a/test/tail.js +++ b/test/tail.js @@ -24,11 +24,11 @@ test('file does not exist', t => { }); test('directory', t => { - t.truthy(fs.statSync('resources/').isDirectory()); // sanity check - const result = shell.tail('resources/'); + t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + const result = shell.tail('test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, "tail: error reading 'resources/': Is a directory"); + t.is(result.stderr, "tail: error reading 'test/resources/': Is a directory"); }); // @@ -45,14 +45,14 @@ const bottomOfFile2 = ['file2 50', 'file2 49', 'file2 48', 'file2 47', 'file2 46 'file2 35', 'file2 34', 'file2 33', 'file2 32', 'file2 31']; test('simple', t => { - const result = shell.tail('resources/head/file1.txt'); + const result = shell.tail('test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), bottomOfFile1.slice(0, 10).reverse().join('\n') + '\n'); }); test('multiple files', t => { - const result = shell.tail('resources/head/file2.txt', 'resources/head/file1.txt'); + const result = shell.tail('test/resources/head/file2.txt', 'test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), @@ -64,7 +64,7 @@ test('multiple files', t => { }); test('multiple files, array syntax', t => { - const result = shell.tail(['resources/head/file2.txt', 'resources/head/file1.txt']); + const result = shell.tail(['test/resources/head/file2.txt', 'test/resources/head/file1.txt']); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), @@ -76,21 +76,21 @@ test('multiple files, array syntax', t => { }); test('reading more lines than are in the file (no trailing newline)', t => { - const result = shell.tail('resources/file2', 'resources/file1'); + const result = shell.tail('test/resources/file2', 'test/resources/file1'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), 'test2\ntest1'); // these files only have one line (no \n) }); test('reading more lines than are in the file (with trailing newline)', t => { - const result = shell.tail('resources/head/shortfile2', 'resources/head/shortfile1'); + const result = shell.tail('test/resources/head/shortfile2', 'test/resources/head/shortfile1'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), 'short2\nshort1\n'); // these files only have one line (with \n) }); test('Globbed file', t => { - const result = shell.tail('resources/head/file?.txt'); + const result = shell.tail('test/resources/head/file?.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), @@ -102,8 +102,8 @@ test('Globbed file', t => { }); test('With `\'-n\' ` option', t => { - const result = shell.tail('-n', 4, 'resources/head/file2.txt', - 'resources/head/file1.txt'); + const result = shell.tail('-n', 4, 'test/resources/head/file2.txt', + 'test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), @@ -115,8 +115,8 @@ test('With `\'-n\' ` option', t => { }); test('With `{\'-n\': }` option', t => { - const result = shell.tail({ '-n': 4 }, 'resources/head/file2.txt', - 'resources/head/file1.txt'); + const result = shell.tail({ '-n': 4 }, 'test/resources/head/file2.txt', + 'test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), @@ -128,8 +128,8 @@ test('With `{\'-n\': }` option', t => { }); test('negative values are the same as positive values', t => { - const result = shell.tail('-n', -4, 'resources/head/file2.txt', - 'resources/head/file1.txt'); + const result = shell.tail('-n', -4, 'test/resources/head/file2.txt', + 'test/resources/head/file1.txt'); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.toString(), diff --git a/test/test.js b/test/test.js index cea2094ed..40a1778cb 100644 --- a/test/test.js +++ b/test/test.js @@ -20,7 +20,7 @@ test('bad expression', t => { }); test('bad expression #2', t => { - shell.test('f', 'resources/file1'); + shell.test('f', 'test/resources/file1'); t.truthy(shell.error()); }); @@ -35,56 +35,56 @@ test('no file', t => { test('-e option succeeds for files', t => { - const result = shell.test('-e', 'resources/file1'); + const result = shell.test('-e', 'test/resources/file1'); t.falsy(shell.error()); t.truthy(result); }); test('-e option fails if it does not exist', t => { - const result = shell.test('-e', 'resources/404'); + const result = shell.test('-e', 'test/resources/404'); t.falsy(shell.error()); t.falsy(result); }); test('-d option succeeds for a directory', t => { - const result = shell.test('-d', 'resources'); + const result = shell.test('-d', 'test/resources'); t.falsy(shell.error()); t.truthy(result); }); test('-f option fails for a directory', t => { - const result = shell.test('-f', 'resources'); + const result = shell.test('-f', 'test/resources'); t.falsy(shell.error()); t.falsy(result); }); test('-L option fails for a directory', t => { - const result = shell.test('-L', 'resources'); + const result = shell.test('-L', 'test/resources'); t.falsy(shell.error()); t.falsy(result); }); test('-d option fails for a file', t => { - const result = shell.test('-d', 'resources/file1'); + const result = shell.test('-d', 'test/resources/file1'); t.falsy(shell.error()); t.falsy(result); }); test('-f option succeeds for a file', t => { - const result = shell.test('-f', 'resources/file1'); + const result = shell.test('-f', 'test/resources/file1'); t.falsy(shell.error()); t.truthy(result); }); test('-L option fails for a file', t => { - const result = shell.test('-L', 'resources/file1'); + const result = shell.test('-L', 'test/resources/file1'); t.falsy(shell.error()); t.falsy(result); }); test('test command is not globbed', t => { // regression #529 - const result = shell.test('-f', 'resources/**/*.js'); + const result = shell.test('-f', 'test/resources/**/*.js'); t.falsy(shell.error()); t.falsy(result); }); @@ -92,7 +92,7 @@ test('test command is not globbed', t => { // TODO(nate): figure out a way to test links on Windows test('-d option fails for a link', t => { utils.skipOnWin(t, () => { - const result = shell.test('-d', 'resources/link'); + const result = shell.test('-d', 'test/resources/link'); t.falsy(shell.error()); t.falsy(result); }); @@ -100,7 +100,7 @@ test('-d option fails for a link', t => { test('-f option succeeds for a link', t => { utils.skipOnWin(t, () => { - const result = shell.test('-f', 'resources/link'); + const result = shell.test('-f', 'test/resources/link'); t.falsy(shell.error()); t.truthy(result); }); @@ -108,7 +108,7 @@ test('-f option succeeds for a link', t => { test('-L option succeeds for a symlink', t => { utils.skipOnWin(t, () => { - const result = shell.test('-L', 'resources/link'); + const result = shell.test('-L', 'test/resources/link'); t.falsy(shell.error()); t.truthy(result); }); @@ -116,7 +116,7 @@ test('-L option succeeds for a symlink', t => { test('-L option works for broken symlinks', t => { utils.skipOnWin(t, () => { - const result = shell.test('-L', 'resources/badlink'); + const result = shell.test('-L', 'test/resources/badlink'); t.falsy(shell.error()); t.truthy(result); }); @@ -124,7 +124,7 @@ test('-L option works for broken symlinks', t => { test('-L option fails for missing files', t => { utils.skipOnWin(t, () => { - const result = shell.test('-L', 'resources/404'); + const result = shell.test('-L', 'test/resources/404'); t.falsy(shell.error()); t.falsy(result); }); diff --git a/test/touch.js b/test/touch.js index 70566ea69..0221170f5 100644 --- a/test/touch.js +++ b/test/touch.js @@ -165,10 +165,10 @@ test('file array', t => { test('touching broken link creates a new file', t => { utils.skipOnWin(t, () => { - const result = shell.touch('resources/badlink'); + const result = shell.touch('test/resources/badlink'); t.is(result.code, 0); t.falsy(shell.error()); - t.truthy(fs.existsSync('resources/not_existed_file')); - shell.rm('resources/not_existed_file'); + t.truthy(fs.existsSync('test/resources/not_existed_file')); + shell.rm('test/resources/not_existed_file'); }); }); diff --git a/test/uniq.js b/test/uniq.js index 751522561..c85df4e27 100644 --- a/test/uniq.js +++ b/test/uniq.js @@ -24,24 +24,24 @@ test('file does not exist', t => { }); test('directory', t => { - t.truthy(fs.statSync('resources/').isDirectory()); // sanity check - const result = shell.uniq('resources/'); + t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + const result = shell.uniq('test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, "uniq: error reading 'resources/'"); + t.is(result.stderr, "uniq: error reading 'test/resources/'"); }); test('output directory', t => { - t.truthy(fs.statSync('resources/').isDirectory()); // sanity check - const result = shell.uniq('resources/file1.txt', 'resources/'); + t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + const result = shell.uniq('test/resources/file1.txt', 'test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); - t.is(result.stderr, 'uniq: resources/: Is a directory'); + t.is(result.stderr, 'uniq: test/resources/: Is a directory'); }); test('file does not exist with output directory', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.uniq('/asdfasdf', 'resources/'); + const result = shell.uniq('/asdfasdf', 'test/resources/'); t.is(result.code, 1); t.truthy(shell.error()); }); @@ -51,53 +51,53 @@ test('file does not exist with output directory', t => { // test('uniq file1', t => { - const result = shell.uniq('resources/uniq/file1'); + const result = shell.uniq('test/resources/uniq/file1'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/uniq/file1u').toString()); + t.is(result.toString(), shell.cat('test/resources/uniq/file1u').toString()); }); test('uniq -i file2', t => { - const result = shell.uniq('-i', 'resources/uniq/file2'); + const result = shell.uniq('-i', 'test/resources/uniq/file2'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/uniq/file2u').toString()); + t.is(result.toString(), shell.cat('test/resources/uniq/file2u').toString()); }); test('with glob character', t => { - const result = shell.uniq('-i', 'resources/uniq/fi?e2'); + const result = shell.uniq('-i', 'test/resources/uniq/fi?e2'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/uniq/file2u').toString()); + t.is(result.toString(), shell.cat('test/resources/uniq/file2u').toString()); }); test('uniq file1 file2', t => { - const result = shell.uniq('resources/uniq/file1', 'resources/uniq/file1t'); + const result = shell.uniq('test/resources/uniq/file1', 'test/resources/uniq/file1t'); t.falsy(shell.error()); t.is(result.code, 0); t.is( - shell.cat('resources/uniq/file1u').toString(), - shell.cat('resources/uniq/file1t').toString() + shell.cat('test/resources/uniq/file1u').toString(), + shell.cat('test/resources/uniq/file1t').toString() ); }); test('cat file1 |uniq', t => { - const result = shell.cat('resources/uniq/file1').uniq(); + const result = shell.cat('test/resources/uniq/file1').uniq(); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/uniq/file1u').toString()); + t.is(result.toString(), shell.cat('test/resources/uniq/file1u').toString()); }); test('uniq -c file1', t => { - const result = shell.uniq('-c', 'resources/uniq/file1'); + const result = shell.uniq('-c', 'test/resources/uniq/file1'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/uniq/file1c').toString()); + t.is(result.toString(), shell.cat('test/resources/uniq/file1c').toString()); }); test('uniq -d file1', t => { - const result = shell.uniq('-d', 'resources/uniq/file1'); + const result = shell.uniq('-d', 'test/resources/uniq/file1'); t.falsy(shell.error()); t.is(result.code, 0); - t.is(result.toString(), shell.cat('resources/uniq/file1d').toString()); + t.is(result.toString(), shell.cat('test/resources/uniq/file1d').toString()); }); From c7d65ac5907bd95294241780deba9cdfb3d2e5a1 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Wed, 23 Aug 2017 19:06:25 -0700 Subject: [PATCH 15/71] fix(ls): ls not following links to directories by default (#764) * Fix ls not following links to directories by default --- src/ls.js | 9 +++++++++ test/ls.js | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/ls.js b/src/ls.js index bb1b6a7bd..8390dc144 100644 --- a/src/ls.js +++ b/src/ls.js @@ -75,6 +75,15 @@ function _ls(options, paths) { try { stat = options.link ? fs.statSync(p) : fs.lstatSync(p); + // follow links to directories by default + if (stat.isSymbolicLink()) { + try { + var _stat = fs.statSync(p); + if (_stat.isDirectory()) { + stat = _stat; + } + } catch (_) {} // bad symlink, treat it like a file + } } catch (e) { common.error('no such file or directory: ' + p, 2, { continue: true }); return; diff --git a/test/ls.js b/test/ls.js index 2131aff3b..4c54c393b 100644 --- a/test/ls.js +++ b/test/ls.js @@ -328,6 +328,16 @@ test('-L flag, path is symlink', t => { }); }); +test('follow links to directories by default', t => { + utils.skipOnWin(t, () => { + const result = shell.ls('test/resources/rm/link_to_a_dir'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.truthy(result.indexOf('a_file') > -1); + t.is(result.length, 1); + }); +}); + test('-Rd works like -d', t => { const result = shell.ls('-Rd', 'test/resources/ls'); t.falsy(shell.error()); From dcead1be86812e5d6498cfffbbd3ac51cfba070f Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Wed, 13 Sep 2017 16:18:28 -0700 Subject: [PATCH 16/71] Add "encoding" option to exec (#763) * Add 'encoding' option to shell.exec * Add 'encoding' option to docs * Add exec encoding option tests * Clarify use of encoding with fs.readFileSync * Add check for stderr buffer --- README.md | 8 +++++--- src/exec.js | 41 +++++++++++++++++++++++------------------ test/exec.js | 21 +++++++++++++++++++++ 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 51082f47c..479fea71b 100644 --- a/README.md +++ b/README.md @@ -273,11 +273,13 @@ like `.to()`. ### exec(command [, options] [, callback]) -Available options (all `false` by default): +Available options: + `async`: Asynchronous execution. If a callback is provided, it will be set to - `true`, regardless of the passed value. -+ `silent`: Do not echo program output to console. + `true`, regardless of the passed value (default: `false`). ++ `silent`: Do not echo program output to console (default: `false`). ++ `encoding`: Character encoding to use. Affects the returned stdout and stderr values, and + what is written to stdout and stderr when not in silent mode (default: `'utf8'`). + and any option available to Node.js's [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) diff --git a/src/exec.js b/src/exec.js index 6a2e1261a..d425b5b21 100644 --- a/src/exec.js +++ b/src/exec.js @@ -34,6 +34,7 @@ function execSync(cmd, opts, pipe) { cwd: _pwd().toString(), env: process.env, maxBuffer: DEFAULT_MAXBUFFER_SIZE, + encoding: 'utf8', }, opts); if (fs.existsSync(scriptFile)) common.unlinkSync(scriptFile); @@ -104,8 +105,17 @@ function execSync(cmd, opts, pipe) { code = parseInt(fs.readFileSync(codeFile, 'utf8'), 10); } - var stdout = fs.readFileSync(stdoutFile, 'utf8'); - var stderr = fs.readFileSync(stderrFile, 'utf8'); + // fs.readFileSync uses buffer encoding by default, so call + // it without the encoding option if the encoding is 'buffer' + var stdout; + var stderr; + if (opts.encoding === 'buffer') { + stdout = fs.readFileSync(stdoutFile); + stderr = fs.readFileSync(stderrFile); + } else { + stdout = fs.readFileSync(stdoutFile, opts.encoding); + stderr = fs.readFileSync(stderrFile, opts.encoding); + } // No biggie if we can't erase the files now -- they're in a temp dir anyway try { common.unlinkSync(scriptFile); } catch (e) {} @@ -122,17 +132,15 @@ function execSync(cmd, opts, pipe) { // Wrapper around exec() to enable echoing output to console in real time function execAsync(cmd, opts, pipe, callback) { - var stdout = ''; - var stderr = ''; - opts = common.extend({ silent: common.config.silent, cwd: _pwd().toString(), env: process.env, maxBuffer: DEFAULT_MAXBUFFER_SIZE, + encoding: 'utf8', }, opts); - var c = child.exec(cmd, opts, function (err) { + var c = child.exec(cmd, opts, function (err, stdout, stderr) { if (callback) { if (!err) { callback(0, stdout, stderr); @@ -148,26 +156,23 @@ function execAsync(cmd, opts, pipe, callback) { if (pipe) c.stdin.end(pipe); - c.stdout.on('data', function (data) { - stdout += data; - if (!opts.silent) process.stdout.write(data); - }); - - c.stderr.on('data', function (data) { - stderr += data; - if (!opts.silent) process.stderr.write(data); - }); + if (!opts.silent) { + c.stdout.pipe(process.stdout); + c.stderr.pipe(process.stderr); + } return c; } //@ //@ ### exec(command [, options] [, callback]) -//@ Available options (all `false` by default): +//@ Available options: //@ //@ + `async`: Asynchronous execution. If a callback is provided, it will be set to -//@ `true`, regardless of the passed value. -//@ + `silent`: Do not echo program output to console. +//@ `true`, regardless of the passed value (default: `false`). +//@ + `silent`: Do not echo program output to console (default: `false`). +//@ + `encoding`: Character encoding to use. Affects the returned stdout and stderr values, and +//@ what is written to stdout and stderr when not in silent mode (default: `'utf8'`). //@ + and any option available to Node.js's //@ [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) //@ diff --git a/test/exec.js b/test/exec.js index e2e8bd1cf..3c73d3612 100644 --- a/test/exec.js +++ b/test/exec.js @@ -163,6 +163,16 @@ test('exec returns a ShellString', t => { t.is(result.toString(), result.stdout); }); +test('encoding option works', t => { + const result = shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.log(1234);"`, { encoding: 'buffer' }); + t.falsy(shell.error()); + t.is(result.code, 0); + t.truthy(Buffer.isBuffer(result.stdout)); + t.truthy(Buffer.isBuffer(result.stderr)); + t.is(result.stdout.toString(), '1234\n'); + t.is(result.stderr.toString(), ''); +}); + // // async // @@ -209,3 +219,14 @@ test.cb('command that fails', t => { t.end(); }); }); + +test.cb('encoding option works with async', t => { + shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.log(5566);"`, { async: true, encoding: 'buffer' }, (code, stdout, stderr) => { + t.is(code, 0); + t.truthy(Buffer.isBuffer(stdout)); + t.truthy(Buffer.isBuffer(stderr)); + t.is(stdout.toString(), '5566\n'); + t.is(stderr.toString(), ''); + t.end(); + }); +}); From c889075f783089831111b28f3bc7528bac72e866 Mon Sep 17 00:00:00 2001 From: cristHian Gz Date: Fri, 22 Sep 2017 23:27:42 -0500 Subject: [PATCH 17/71] feat(cat): number output lines (#750) (#775) --- README.md | 7 ++++-- src/cat.js | 37 ++++++++++++++++++++++++++-- test/cat.js | 53 ++++++++++++++++++++++++++++++++++++++++ test/ls.js | 5 +++- test/resources/cat/file3 | 1 + test/resources/cat/file4 | 12 +++++++++ test/resources/cat/file5 | 0 7 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 test/resources/cat/file3 create mode 100644 test/resources/cat/file4 create mode 100644 test/resources/cat/file5 diff --git a/README.md b/README.md index 479fea71b..c52c12a8e 100644 --- a/README.md +++ b/README.md @@ -121,8 +121,11 @@ For less-commonly used commands and features, please check out our [wiki page](https://github.com/shelljs/shelljs/wiki). -### cat(file [, file ...]) -### cat(file_array) +### cat([options,] file [, file ...]) +### cat([options,] file_array) +Available options: + ++ `-n`: number all output lines Examples: diff --git a/src/cat.js b/src/cat.js index af1ad1d4d..fd8ec28c6 100644 --- a/src/cat.js +++ b/src/cat.js @@ -3,11 +3,17 @@ var fs = require('fs'); common.register('cat', _cat, { canReceivePipe: true, + cmdOptions: { + 'n': 'number', + }, }); //@ -//@ ### cat(file [, file ...]) -//@ ### cat(file_array) +//@ ### cat([options,] file [, file ...]) +//@ ### cat([options,] file_array) +//@ Available options: +//@ +//@ + `-n`: number all output lines //@ //@ Examples: //@ @@ -37,6 +43,33 @@ function _cat(options, files) { cat += fs.readFileSync(file, 'utf8'); }); + if (options.number) { + cat = addNumbers(cat); + } + return cat; } module.exports = _cat; + +function addNumbers(cat) { + var lines = cat.split('\n'); + var lastLine = lines.pop(); + + lines = lines.map(function (line, i) { + return numberedLine(i + 1, line); + }); + + if (lastLine.length) { + lastLine = numberedLine(lines.length + 1, lastLine); + } + lines.push(lastLine); + + return lines.join('\n'); +} + +function numberedLine(n, line) { + // GNU cat use six pad start number + tab. See http://lingrok.org/xref/coreutils/src/cat.c#57 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart + var number = (' ' + n).slice(-6) + '\t'; + return number + line; +} diff --git a/test/cat.js b/test/cat.js index c61905f6a..cc21ce575 100644 --- a/test/cat.js +++ b/test/cat.js @@ -64,3 +64,56 @@ test('glob', t => { t.truthy(result.search('test1') > -1); // file order might be random t.truthy(result.search('test2') > -1); }); + +test('without EOF', t => { + const result = shell.cat('test/resources/cat/file3'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(result.toString(), 'test3'); +}); + +test('empty', t => { + const result = shell.cat('test/resources/cat/file5'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(result.toString(), ''); +}); + +// +// With numbers +// + +test('simple with numbers', t => { + const result = shell.cat('-n', 'test/resources/cat/file1'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(result.toString(), ' 1\ttest1\n'); +}); + +test('simple twelve lines file with numbers', t => { + const result = shell.cat('-n', 'test/resources/cat/file4'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(result.toString(), ' 1\ttest4-01\n 2\ttest4-02\n 3\ttest4-03\n 4\ttest4-04\n 5\ttest4-05\n 6\ttest4-06\n 7\ttest4-07\n 8\ttest4-08\n 9\ttest4-09\n 10\ttest4-10\n 11\ttest4-11\n 12\ttest4-12\n'); +}); + +test('multiple with numbers', t => { + const result = shell.cat('-n', 'test/resources/cat/file2', 'test/resources/cat/file1'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(result.toString(), ' 1\ttest2\n 2\ttest1\n'); +}); + +test('simple numbers without EOF', t => { + const result = shell.cat('-n', 'test/resources/cat/file3'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(result.toString(), ' 1\ttest3'); +}); + +test('multiple numbers without EOF', t => { + const result = shell.cat('-n', 'test/resources/cat/file3', 'test/resources/cat/file2', 'test/resources/cat/file1'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.is(result.toString(), ' 1\ttest3test2\n 2\ttest1\n'); +}); diff --git a/test/ls.js b/test/ls.js index 4c54c393b..dbc557679 100644 --- a/test/ls.js +++ b/test/ls.js @@ -125,7 +125,10 @@ test('wildcard, very simple', t => { t.is(result.code, 0); t.truthy(result.indexOf('test/resources/cat/file1') > -1); t.truthy(result.indexOf('test/resources/cat/file2') > -1); - t.is(result.length, 2); + t.truthy(result.indexOf('test/resources/cat/file3') > -1); + t.truthy(result.indexOf('test/resources/cat/file4') > -1); + t.truthy(result.indexOf('test/resources/cat/file5') > -1); + t.is(result.length, 5); }); test('wildcard, simple', t => { diff --git a/test/resources/cat/file3 b/test/resources/cat/file3 new file mode 100644 index 000000000..29f446afe --- /dev/null +++ b/test/resources/cat/file3 @@ -0,0 +1 @@ +test3 \ No newline at end of file diff --git a/test/resources/cat/file4 b/test/resources/cat/file4 new file mode 100644 index 000000000..f4538a5cc --- /dev/null +++ b/test/resources/cat/file4 @@ -0,0 +1,12 @@ +test4-01 +test4-02 +test4-03 +test4-04 +test4-05 +test4-06 +test4-07 +test4-08 +test4-09 +test4-10 +test4-11 +test4-12 diff --git a/test/resources/cat/file5 b/test/resources/cat/file5 new file mode 100644 index 000000000..e69de29bb From cea0e58250b357e916ecef7c4e75294632af4597 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Tue, 10 Oct 2017 04:53:17 +0100 Subject: [PATCH 18/71] Added `-q` (quiet) option to `push`, `popd`, `dirs` functions. (#777) * Added `-q` (quiet) option to `push`, `popd`, `dirs` functions. * Added unit tests for pushd/popd quiet mode. * Added tests for `pushd` and `popd` with quiet mode off. * Updated docs for `pushd` and `popd` functions. * Moved preliminary `pushd` commands for `popd` tests before disabling of silent flag. --- README.md | 3 +++ src/dirs.js | 18 ++++++++++++++---- test/popd.js | 39 +++++++++++++++++++++++++++++++++++++++ test/pushd.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c52c12a8e..36087920e 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,7 @@ Copies files. Available options: + `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated. ++ `-q`: Supresses output to the console. Arguments: @@ -223,6 +224,7 @@ Save the current directory on the top of the directory stack and then cd to `dir Available options: + `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. ++ `-q`: Supresses output to the console. Arguments: @@ -246,6 +248,7 @@ When no arguments are given, popd removes the top directory from the stack and p Available options: + `-c`: Clears the directory stack by deleting all of the elements. ++ `-q`: Supresses output to the console. Arguments: diff --git a/src/dirs.js b/src/dirs.js index 3806c14f7..3e27ac95e 100644 --- a/src/dirs.js +++ b/src/dirs.js @@ -40,6 +40,7 @@ function _actualDirStack() { //@ Available options: //@ //@ + `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated. +//@ + `-q`: Supresses output to the console. //@ //@ Arguments: //@ @@ -64,6 +65,7 @@ function _pushd(options, dir) { options = common.parseOptions(options, { 'n': 'no-cd', + 'q': 'quiet', }); var dirs = _actualDirStack(); @@ -95,7 +97,7 @@ function _pushd(options, dir) { } _dirStack = dirs; - return _dirs(''); + return _dirs(options.quiet ? '-q' : ''); } exports.pushd = _pushd; @@ -105,6 +107,7 @@ exports.pushd = _pushd; //@ Available options: //@ //@ + `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. +//@ + `-q`: Supresses output to the console. //@ //@ Arguments: //@ @@ -130,6 +133,7 @@ function _popd(options, index) { options = common.parseOptions(options, { 'n': 'no-cd', + 'q': 'quiet', }); if (!_dirStack.length) { @@ -146,7 +150,7 @@ function _popd(options, index) { _cd('', dir); } - return _dirs(''); + return _dirs(options.quiet ? '-q' : ''); } exports.popd = _popd; @@ -156,6 +160,7 @@ exports.popd = _popd; //@ Available options: //@ //@ + `-c`: Clears the directory stack by deleting all of the elements. +//@ + `-q`: Supresses output to the console. //@ //@ Arguments: //@ @@ -173,6 +178,7 @@ function _dirs(options, index) { options = common.parseOptions(options, { 'c': 'clear', + 'q': 'quiet', }); if (options.clear) { @@ -189,11 +195,15 @@ function _dirs(options, index) { index = stack.length + index; } - common.log(stack[index]); + if (!options.quiet) { + common.log(stack[index]); + } return stack[index]; } - common.log(stack.join(' ')); + if (!options.quiet) { + common.log(stack.join(' ')); + } return stack; } diff --git a/test/popd.js b/test/popd.js index 0e83a7cfa..0626a0bec 100644 --- a/test/popd.js +++ b/test/popd.js @@ -3,6 +3,7 @@ import path from 'path'; import test from 'ava'; import shell from '..'; +import mocks from './utils/mocks'; const rootDir = path.resolve(); @@ -114,3 +115,41 @@ test('Test that rootDir is not stored', t => { shell.popd(); // no more in the stack t.truthy(shell.error()); }); + +test('quiet mode off', t => { + try { + shell.pushd('test/resources/pushd'); + shell.config.silent = false; + mocks.init(); + const trail = shell.popd(); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(stdout, ''); + t.is(stderr, `${rootDir}\n`); + t.is(process.cwd(), trail[0]); + t.deepEqual(trail, [rootDir]); + } finally { + shell.config.silent = true; + mocks.restore(); + } +}); + +test('quiet mode on', t => { + try { + shell.pushd('test/resources/pushd'); + shell.config.silent = false; + mocks.init(); + const trail = shell.popd('-q'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(stdout, ''); + t.is(stderr, ''); + t.is(process.cwd(), trail[0]); + t.deepEqual(trail, [rootDir]); + } finally { + shell.config.silent = true; + mocks.restore(); + } +}); diff --git a/test/pushd.js b/test/pushd.js index 9ca0f76b0..d24b321fc 100644 --- a/test/pushd.js +++ b/test/pushd.js @@ -3,6 +3,7 @@ import path from 'path'; import test from 'ava'; import shell from '..'; +import mocks from './utils/mocks'; const rootDir = path.resolve(); @@ -328,3 +329,45 @@ test('Push without arguments invalid when stack is empty', t => { shell.pushd(); t.is(shell.error(), 'pushd: no other directory'); }); + +test('quiet mode off', t => { + try { + shell.config.silent = false; + mocks.init(); + const trail = shell.pushd('test/resources/pushd'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(stdout, ''); + t.is(stderr, `${path.resolve(rootDir, 'test/resources/pushd')} ${rootDir}\n`); + t.is(process.cwd(), trail[0]); + t.deepEqual(trail, [ + path.resolve(rootDir, 'test/resources/pushd'), + rootDir, + ]); + } finally { + shell.config.silent = true; + mocks.restore(); + } +}); + +test('quiet mode on', t => { + try { + shell.config.silent = false; + mocks.init(); + const trail = shell.pushd('-q', 'test/resources/pushd'); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.falsy(shell.error()); + t.is(stdout, ''); + t.is(stderr, ''); + t.is(process.cwd(), trail[0]); + t.deepEqual(trail, [ + path.resolve(rootDir, 'test/resources/pushd'), + rootDir, + ]); + } finally { + shell.config.silent = true; + mocks.restore(); + } +}); From cd1aabab3972f55197db6b9168817175c545af6c Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 12 Oct 2017 23:23:09 -0700 Subject: [PATCH 19/71] chore: set AVA options (#780) This sets 2 AVA options: * `serial`: same behavior as the CLI flag, which this replaces * `powerAssert`: if an assert fails, it will inspect all objects involved in the failed assert. This causes readability issues if `t.falsy(shell.error())` breaks, since it inspects all of `shell` (which is way too large). AVA options are a little easier to manage than CLI options (we only update one place instead of 2 in `package.json`). --- package.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6303ffe1c..eea927891 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,8 @@ ], "scripts": { "posttest": "npm run lint", - "test": "nyc --reporter=text --reporter=lcov ava --serial test/*.js", - "test-no-coverage": "ava --serial test/*.js", + "test": "nyc --reporter=text --reporter=lcov ava test/*.js", + "test-no-coverage": "ava test/*.js", "gendocs": "node scripts/generate-docs", "lint": "eslint .", "after-travis": "travis-check-changes", @@ -53,6 +53,10 @@ "interpret": "^1.0.0", "rechoir": "^0.6.2" }, + "ava": { + "serial": true, + "powerAssert": false + }, "devDependencies": { "ava": "^0.21.0", "chalk": "^1.1.3", From df1460ff538483628375c2c42e98f74face17ffc Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 12 Oct 2017 23:23:23 -0700 Subject: [PATCH 20/71] chore: clean up refs to unsupported node versions (#779) Also removes unnecessary guard code leftover from old versions. --- src/tempdir.js | 2 +- test/exec.js | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tempdir.js b/src/tempdir.js index b3a6cca38..fad35e924 100644 --- a/src/tempdir.js +++ b/src/tempdir.js @@ -40,7 +40,7 @@ function _tempDir() { var state = common.state; if (state.tempDir) return state.tempDir; // from cache - state.tempDir = writeableDir(os.tmpdir && os.tmpdir()) || // node 0.10+ + state.tempDir = writeableDir(os.tmpdir()) || writeableDir(process.env.TMPDIR) || writeableDir(process.env.TEMP) || writeableDir(process.env.TMP) || diff --git a/test/exec.js b/test/exec.js index 3c73d3612..f2a1c00f3 100644 --- a/test/exec.js +++ b/test/exec.js @@ -121,10 +121,7 @@ test('set timeout option', t => { const result = shell.exec(`${JSON.stringify(shell.config.execPath)} test/resources/exec/slow.js 100`); // default timeout is ok t.falsy(shell.error()); t.is(result.code, 0); - if (process.version >= 'v0.11') { - // this option doesn't work on v0.10 - shell.exec(`${JSON.stringify(shell.config.execPath)} test/resources/exec/slow.js 100`, { timeout: 10 }); // times out - } + shell.exec(`${JSON.stringify(shell.config.execPath)} test/resources/exec/slow.js 100`, { timeout: 10 }); // times out t.truthy(shell.error()); }); @@ -145,7 +142,6 @@ test('set shell option (TODO: add tests for Windows)', t => { t.is(result.code, 0); t.is(result.stdout, '/bin/sh\n'); // sh by default const bashPath = shell.which('bash').trim(); - // this option doesn't work on v0.10 if (bashPath) { result = shell.exec('echo $0', { shell: '/bin/bash' }); t.falsy(shell.error()); From 32972e0cdda0a37ba3a8277d6ca1b134ad964e7f Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Sat, 14 Oct 2017 02:38:12 -0700 Subject: [PATCH 21/71] Remove unnecessary shell.error checks from common tests (#785) --- test/common.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/common.js b/test/common.js index 7f8fb1364..b433f91ba 100644 --- a/test/common.js +++ b/test/common.js @@ -139,25 +139,21 @@ test('convertErrorOutput: changes backslashes to forward slashes', t => { // test('single file, array syntax', t => { const result = common.expand(['test/resources/file1.txt']); - t.falsy(shell.error()); t.deepEqual(result, ['test/resources/file1.txt']); }); test('multiple file, glob syntax, * for file name', t => { const result = common.expand(['test/resources/file*.txt']); - t.falsy(shell.error()); t.deepEqual(result.sort(), ['test/resources/file1.txt', 'test/resources/file2.txt'].sort()); }); test('multiple file, glob syntax, * for directory name', t => { const result = common.expand(['test/r*/file*.txt']); - t.falsy(shell.error()); t.deepEqual(result.sort(), ['test/resources/file1.txt', 'test/resources/file2.txt'].sort()); }); test('multiple file, glob syntax, ** for directory name', t => { const result = common.expand(['test/resources/**/file*.js']); - t.falsy(shell.error()); t.deepEqual( result.sort(), ['test/resources/file1.js', 'test/resources/file2.js', 'test/resources/ls/file1.js', 'test/resources/ls/file2.js'].sort() @@ -166,25 +162,21 @@ test('multiple file, glob syntax, ** for directory name', t => { test('broken links still expand', t => { const result = common.expand(['test/resources/b*dlink']); - t.falsy(shell.error()); t.deepEqual(result, ['test/resources/badlink']); }); test('empty array', t => { const result = common.expand([]); - t.falsy(shell.error()); t.deepEqual(result, []); }); test('empty string', t => { const result = common.expand(['']); - t.falsy(shell.error()); t.deepEqual(result, ['']); }); test('non-string', t => { const result = common.expand([5]); - t.falsy(shell.error()); t.deepEqual(result, [5]); }); @@ -193,14 +185,12 @@ test('non-string', t => { // test('common.buffer returns buffer', t => { const buf = common.buffer(); - t.falsy(shell.error()); t.truthy(buf instanceof Buffer); t.is(buf.length, 64 * 1024); }); test('common.buffer with explicit length', t => { const buf = common.buffer(20); - t.falsy(shell.error()); t.truthy(buf instanceof Buffer); t.is(buf.length, 20); }); @@ -208,7 +198,6 @@ test('common.buffer with explicit length', t => { test('common.buffer with different config.bufLength', t => { common.config.bufLength = 20; const buf = common.buffer(); - t.falsy(shell.error()); t.truthy(buf instanceof Buffer); t.is(buf.length, 20); common.config.reset(); From 7cbce889150a16f096cf1af15a88e12ef77c4f03 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Tue, 17 Oct 2017 19:22:37 -0700 Subject: [PATCH 22/71] Add a test for ls for a single file (#784) --- test/ls.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/ls.js b/test/ls.js index dbc557679..2cdc1933c 100644 --- a/test/ls.js +++ b/test/ls.js @@ -87,6 +87,14 @@ test('simple arg, with a trailing slash', t => { t.is(result.length, 6); }); +test('simple arg, a file', t => { + const result = shell.ls('test/resources/ls/file1'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.truthy(result.indexOf('test/resources/ls/file1') > -1); + t.is(result.length, 1); +}); + test('no args, -A option', t => { shell.cd('test/resources/ls'); const result = shell.ls('-A'); From a7d6df5f6de35bdbf279b7640218856af64cc868 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Tue, 17 Oct 2017 19:25:09 -0700 Subject: [PATCH 23/71] Wrap fs.statSync and fs.lstatSync (#783) Adds two new methods to src/common.js, common.statFollowLinks and common.statNoFollowLinks, which wrap fs.statSync and fs.lstatSync, respectively. This change is meant to improve readability and clarify intent. * Add common.statFollowLinks and common.statNoFollowLinks * Replace fs.statSync and fs.lstatSync in source files --- src/cat.js | 2 +- src/cd.js | 3 +-- src/chmod.js | 10 ++++---- src/common.js | 12 ++++++++++ src/cp.js | 26 ++++++++++---------- src/find.js | 3 +-- src/head.js | 2 +- src/ln.js | 2 +- src/ls.js | 6 ++--- src/mkdir.js | 2 +- src/mv.js | 4 ++-- src/rm.js | 6 ++--- src/sort.js | 2 +- src/tail.js | 2 +- src/tempdir.js | 2 +- src/test.js | 4 ++-- src/touch.js | 2 +- src/uniq.js | 4 ++-- src/which.js | 2 +- test/chmod.js | 65 +++++++++++++++++++++++++------------------------- test/cp.js | 49 ++++++++++++++++++------------------- test/head.js | 3 ++- test/ls.js | 3 ++- test/mkdir.js | 21 ++++++++-------- test/sort.js | 3 ++- test/tail.js | 3 ++- test/touch.js | 27 +++++++++++---------- test/uniq.js | 5 ++-- 28 files changed, 147 insertions(+), 128 deletions(-) diff --git a/src/cat.js b/src/cat.js index fd8ec28c6..cdad1b0f6 100644 --- a/src/cat.js +++ b/src/cat.js @@ -36,7 +36,7 @@ function _cat(options, files) { files.forEach(function (file) { if (!fs.existsSync(file)) { common.error('no such file or directory: ' + file); - } else if (fs.statSync(file).isDirectory()) { + } else if (common.statFollowLinks(file).isDirectory()) { common.error(file + ': Is a directory'); } diff --git a/src/cd.js b/src/cd.js index c6f1ada33..87ce9b9a7 100644 --- a/src/cd.js +++ b/src/cd.js @@ -1,4 +1,3 @@ -var fs = require('fs'); var os = require('os'); var common = require('./common'); @@ -27,7 +26,7 @@ function _cd(options, dir) { // something went wrong, let's figure out the error var err; try { - fs.statSync(dir); // if this succeeds, it must be some sort of file + common.statFollowLinks(dir); // if this succeeds, it must be some sort of file err = 'not a directory: ' + dir; } catch (e2) { err = 'no such file or directory: ' + dir; diff --git a/src/chmod.js b/src/chmod.js index ce5659e35..758c6e515 100644 --- a/src/chmod.js +++ b/src/chmod.js @@ -85,7 +85,7 @@ function _chmod(options, mode, filePattern) { if (options.recursive) { files = []; filePattern.forEach(function addFile(expandedFile) { - var stat = fs.lstatSync(expandedFile); + var stat = common.statNoFollowLinks(expandedFile); if (!stat.isSymbolicLink()) { files.push(expandedFile); @@ -108,11 +108,11 @@ function _chmod(options, mode, filePattern) { } // When recursing, don't follow symlinks. - if (options.recursive && fs.lstatSync(file).isSymbolicLink()) { + if (options.recursive && common.statNoFollowLinks(file).isSymbolicLink()) { return; } - var stat = fs.statSync(file); + var stat = common.statFollowLinks(file); var isDir = stat.isDirectory(); var perms = stat.mode; var type = perms & PERMS.TYPE_MASK; @@ -175,7 +175,7 @@ function _chmod(options, mode, filePattern) { // According to POSIX, when using = to explicitly set the // permissions, setuid and setgid can never be cleared. - if (fs.statSync(file).isDirectory()) { + if (common.statFollowLinks(file).isDirectory()) { newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms; } break; @@ -204,7 +204,7 @@ function _chmod(options, mode, filePattern) { // POSIX rules are that setuid and setgid can only be added using numeric // form, but not cleared. - if (fs.statSync(file).isDirectory()) { + if (common.statFollowLinks(file).isDirectory()) { newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms; } diff --git a/src/common.js b/src/common.js index 13753a12f..77e0306e4 100644 --- a/src/common.js +++ b/src/common.js @@ -277,6 +277,18 @@ function unlinkSync(file) { } exports.unlinkSync = unlinkSync; +// wrappers around common.statFollowLinks and common.statNoFollowLinks that clarify intent +// and improve readability +function statFollowLinks() { + return fs.statSync.apply(fs, arguments); +} +exports.statFollowLinks = statFollowLinks; + +function statNoFollowLinks() { + return fs.lstatSync.apply(fs, arguments); +} +exports.statNoFollowLinks = statNoFollowLinks; + // e.g. 'shelljs_a5f185d0443ca...' function randomFileName() { function randomHash(count) { diff --git a/src/cp.js b/src/cp.js index 99c97b2eb..d46a54ab5 100644 --- a/src/cp.js +++ b/src/cp.js @@ -27,16 +27,16 @@ function copyFileSync(srcFile, destFile, options) { // Check the mtimes of the files if the '-u' flag is provided try { - if (options.update && fs.statSync(srcFile).mtime < fs.statSync(destFile).mtime) { + if (options.update && common.statFollowLinks(srcFile).mtime < fs.statSync(destFile).mtime) { return; } } catch (e) { // If we're here, destFile probably doesn't exist, so just do a normal copy } - if (fs.lstatSync(srcFile).isSymbolicLink() && !options.followsymlink) { + if (common.statNoFollowLinks(srcFile).isSymbolicLink() && !options.followsymlink) { try { - fs.lstatSync(destFile); + common.statNoFollowLinks(destFile); common.unlinkSync(destFile); // re-link it } catch (e) { // it doesn't exist, so no work needs to be done @@ -75,7 +75,7 @@ function copyFileSync(srcFile, destFile, options) { fs.closeSync(fdr); fs.closeSync(fdw); - fs.chmodSync(destFile, fs.statSync(srcFile).mode); + fs.chmodSync(destFile, common.statFollowLinks(srcFile).mode); } } @@ -99,7 +99,7 @@ function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { // Create the directory where all our junk is moving to; read the mode of the // source directory and mirror it try { - var checkDir = fs.statSync(sourceDir); + var checkDir = common.statFollowLinks(sourceDir); fs.mkdirSync(destDir, checkDir.mode); } catch (e) { // if the directory already exists, that's okay @@ -111,7 +111,7 @@ function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { for (var i = 0; i < files.length; i++) { var srcFile = sourceDir + '/' + files[i]; var destFile = destDir + '/' + files[i]; - var srcFileStat = fs.lstatSync(srcFile); + var srcFileStat = common.statNoFollowLinks(srcFile); var symlinkFull; if (opts.followsymlink) { @@ -129,14 +129,14 @@ function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { } else if (srcFileStat.isSymbolicLink() && !opts.followsymlink) { symlinkFull = fs.readlinkSync(srcFile); try { - fs.lstatSync(destFile); + common.statNoFollowLinks(destFile); common.unlinkSync(destFile); // re-link it } catch (e) { // it doesn't exist, so no work needs to be done } fs.symlinkSync(symlinkFull, destFile, isWindows ? 'junction' : null); } else if (srcFileStat.isSymbolicLink() && opts.followsymlink) { - srcFileStat = fs.statSync(srcFile); + srcFileStat = common.statFollowLinks(srcFile); if (srcFileStat.isDirectory()) { cpdirSyncRecursive(srcFile, destFile, currentDepth, opts); } else { @@ -162,7 +162,7 @@ function checkRecentCreated(sources, index) { } function cpcheckcycle(sourceDir, srcFile) { - var srcFileStat = fs.lstatSync(srcFile); + var srcFileStat = common.statNoFollowLinks(srcFile); if (srcFileStat.isSymbolicLink()) { // Do cycle check. For example: // $ mkdir -p 1/2/3/4 @@ -170,7 +170,7 @@ function cpcheckcycle(sourceDir, srcFile) { // $ ln -s ../../3 link // $ cd ../../../.. // $ cp -RL 1 copy - var cyclecheck = fs.statSync(srcFile); + var cyclecheck = common.statFollowLinks(srcFile); if (cyclecheck.isDirectory()) { var sourcerealpath = fs.realpathSync(sourceDir); var symlinkrealpath = fs.realpathSync(srcFile); @@ -223,7 +223,7 @@ function _cp(options, sources, dest) { } var destExists = fs.existsSync(dest); - var destStat = destExists && fs.statSync(dest); + var destStat = destExists && common.statFollowLinks(dest); // Dest is not existing dir, but multiple sources given if ((!destExists || !destStat.isDirectory()) && sources.length > 1) { @@ -241,7 +241,7 @@ function _cp(options, sources, dest) { common.error('no such file or directory: ' + src, { continue: true }); return; // skip file } - var srcStat = fs.statSync(src); + var srcStat = common.statFollowLinks(src); if (!options.noFollowsymlink && srcStat.isDirectory()) { if (!options.recursive) { // Non-Recursive @@ -254,7 +254,7 @@ function _cp(options, sources, dest) { dest; try { - fs.statSync(path.dirname(dest)); + common.statFollowLinks(path.dirname(dest)); cpdirSyncRecursive(src, newDest, 0, { no_force: options.no_force, followsymlink: options.followsymlink }); } catch (e) { /* istanbul ignore next */ diff --git a/src/find.js b/src/find.js index 76a16c4ee..b28d0378e 100644 --- a/src/find.js +++ b/src/find.js @@ -1,4 +1,3 @@ -var fs = require('fs'); var path = require('path'); var common = require('./common'); var _ls = require('./ls'); @@ -42,7 +41,7 @@ function _find(options, paths) { paths.forEach(function (file) { var stat; try { - stat = fs.statSync(file); + stat = common.statFollowLinks(file); } catch (e) { common.error('no such file or directory: ' + file); } diff --git a/src/head.js b/src/head.js index 2640b13b4..c08ae9ba3 100644 --- a/src/head.js +++ b/src/head.js @@ -71,7 +71,7 @@ function _head(options, files) { if (!fs.existsSync(file)) { common.error('no such file or directory: ' + file, { continue: true }); return; - } else if (fs.statSync(file).isDirectory()) { + } else if (common.statFollowLinks(file).isDirectory()) { common.error("error reading '" + file + "': Is a directory", { continue: true, }); diff --git a/src/ln.js b/src/ln.js index 9b8beb9ec..71f2b3916 100644 --- a/src/ln.js +++ b/src/ln.js @@ -48,7 +48,7 @@ function _ln(options, source, dest) { var resolvedSourcePath = isAbsolute ? sourcePath : path.resolve(process.cwd(), path.dirname(dest), source); if (!fs.existsSync(resolvedSourcePath)) { common.error('Source file does not exist', { continue: true }); - } else if (isWindows && fs.statSync(resolvedSourcePath).isDirectory()) { + } else if (isWindows && common.statFollowLinks(resolvedSourcePath).isDirectory()) { linkType = 'junction'; } diff --git a/src/ls.js b/src/ls.js index 8390dc144..2f3ac6973 100644 --- a/src/ls.js +++ b/src/ls.js @@ -62,7 +62,7 @@ function _ls(options, paths) { relName = relName.replace(/\\/g, '/'); } if (options.long) { - stat = stat || (options.link ? fs.statSync(abs) : fs.lstatSync(abs)); + stat = stat || (options.link ? common.statFollowLinks(abs) : common.statNoFollowLinks(abs)); list.push(addLsAttributes(relName, stat)); } else { // list.push(path.relative(rel || '.', file)); @@ -74,11 +74,11 @@ function _ls(options, paths) { var stat; try { - stat = options.link ? fs.statSync(p) : fs.lstatSync(p); + stat = options.link ? common.statFollowLinks(p) : common.statNoFollowLinks(p); // follow links to directories by default if (stat.isSymbolicLink()) { try { - var _stat = fs.statSync(p); + var _stat = common.statFollowLinks(p); if (_stat.isDirectory()) { stat = _stat; } diff --git a/src/mkdir.js b/src/mkdir.js index 44b1b2162..723c137d2 100644 --- a/src/mkdir.js +++ b/src/mkdir.js @@ -57,7 +57,7 @@ function _mkdir(options, dirs) { dirs.forEach(function (dir) { try { - var stat = fs.lstatSync(dir); + var stat = common.statNoFollowLinks(dir); if (!options.fullpath) { common.error('path already exists: ' + dir, { continue: true }); } else if (stat.isFile()) { diff --git a/src/mv.js b/src/mv.js index 6ebaa8a03..525be06b8 100644 --- a/src/mv.js +++ b/src/mv.js @@ -51,7 +51,7 @@ function _mv(options, sources, dest) { } var exists = fs.existsSync(dest); - var stats = exists && fs.statSync(dest); + var stats = exists && common.statFollowLinks(dest); // Dest is not existing dir, but multiple sources given if ((!exists || !stats.isDirectory()) && sources.length > 1) { @@ -74,7 +74,7 @@ function _mv(options, sources, dest) { // When copying to '/path/dir': // thisDest = '/path/dir/file1' var thisDest = dest; - if (fs.existsSync(dest) && fs.statSync(dest).isDirectory()) { + if (fs.existsSync(dest) && common.statFollowLinks(dest).isDirectory()) { thisDest = path.normalize(dest + '/' + path.basename(src)); } diff --git a/src/rm.js b/src/rm.js index 2ad6914b4..75dcd7fa4 100644 --- a/src/rm.js +++ b/src/rm.js @@ -25,7 +25,7 @@ function rmdirSyncRecursive(dir, force, fromSymlink) { // Loop through and delete everything in the sub-tree after checking it for (var i = 0; i < files.length; i++) { var file = dir + '/' + files[i]; - var currFile = fs.lstatSync(file); + var currFile = common.statNoFollowLinks(file); if (currFile.isDirectory()) { // Recursive function back to the beginning rmdirSyncRecursive(file, force); @@ -116,7 +116,7 @@ function handleDirectory(file, options) { function handleSymbolicLink(file, options) { var stats; try { - stats = fs.statSync(file); + stats = common.statFollowLinks(file); } catch (e) { // symlink is broken, so remove the symlink itself common.unlinkSync(file); @@ -175,7 +175,7 @@ function _rm(options, files) { var filepath = (file[file.length - 1] === '/') ? file.slice(0, -1) // remove the '/' so lstatSync can detect symlinks : file; - lstats = fs.lstatSync(filepath); // test for existence + lstats = common.statNoFollowLinks(filepath); // test for existence } catch (e) { // Path does not exist, no force flag given if (!options.force) { diff --git a/src/sort.js b/src/sort.js index 5dd8d75fc..e0feed746 100644 --- a/src/sort.js +++ b/src/sort.js @@ -72,7 +72,7 @@ function _sort(options, files) { if (!fs.existsSync(file)) { common.error('no such file or directory: ' + file, { continue: true }); return accum; - } else if (fs.statSync(file).isDirectory()) { + } else if (common.statFollowLinks(file).isDirectory()) { common.error('read failed: ' + file + ': Is a directory', { continue: true, }); diff --git a/src/tail.js b/src/tail.js index e5a88055c..5e0256e76 100644 --- a/src/tail.js +++ b/src/tail.js @@ -50,7 +50,7 @@ function _tail(options, files) { if (!fs.existsSync(file)) { common.error('no such file or directory: ' + file, { continue: true }); return; - } else if (fs.statSync(file).isDirectory()) { + } else if (common.statFollowLinks(file).isDirectory()) { common.error("error reading '" + file + "': Is a directory", { continue: true, }); diff --git a/src/tempdir.js b/src/tempdir.js index fad35e924..6fe116fe2 100644 --- a/src/tempdir.js +++ b/src/tempdir.js @@ -11,7 +11,7 @@ common.register('tempdir', _tempDir, { function writeableDir(dir) { if (!dir || !fs.existsSync(dir)) return false; - if (!fs.statSync(dir).isDirectory()) return false; + if (!common.statFollowLinks(dir).isDirectory()) return false; var testFile = dir + '/' + common.randomFileName(); try { diff --git a/src/test.js b/src/test.js index d3d9c07a0..c0c6469f8 100644 --- a/src/test.js +++ b/src/test.js @@ -52,7 +52,7 @@ function _test(options, path) { if (options.link) { try { - return fs.lstatSync(path).isSymbolicLink(); + return common.statNoFollowLinks(path).isSymbolicLink(); } catch (e) { return false; } @@ -62,7 +62,7 @@ function _test(options, path) { if (options.exists) return true; - var stats = fs.statSync(path); + var stats = common.statFollowLinks(path); if (options.block) return stats.isBlockDevice(); diff --git a/src/touch.js b/src/touch.js index b672b2d25..dd6b8bc54 100644 --- a/src/touch.js +++ b/src/touch.js @@ -103,7 +103,7 @@ module.exports = _touch; function tryStatFile(filePath) { try { - return fs.statSync(filePath); + return common.statFollowLinks(filePath); } catch (e) { return null; } diff --git a/src/uniq.js b/src/uniq.js index 8c0f04010..2a287ce15 100644 --- a/src/uniq.js +++ b/src/uniq.js @@ -45,11 +45,11 @@ function _uniq(options, input, output) { if (!fs.existsSync(input)) { common.error(input + ': No such file or directory'); - } else if (fs.statSync(input).isDirectory()) { + } else if (common.statFollowLinks(input).isDirectory()) { common.error("error reading '" + input + "'"); } } - if (output && fs.existsSync(output) && fs.statSync(output).isDirectory()) { + if (output && fs.existsSync(output) && common.statFollowLinks(output).isDirectory()) { common.error(output + ': Is a directory'); } diff --git a/src/which.js b/src/which.js index a5f9e15eb..e6ae9eb58 100644 --- a/src/which.js +++ b/src/which.js @@ -19,7 +19,7 @@ function splitPath(p) { } function checkPath(pathName) { - return fs.existsSync(pathName) && !fs.statSync(pathName).isDirectory(); + return fs.existsSync(pathName) && !common.statFollowLinks(pathName).isDirectory(); } //@ diff --git a/test/chmod.js b/test/chmod.js index 7b617ab3a..5c0905e8b 100644 --- a/test/chmod.js +++ b/test/chmod.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import common from '../src/common'; import utils from './utils/utils'; let TMP; @@ -36,13 +37,13 @@ test('Basic usage with octal codes', t => { let result = shell.chmod('755', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & BITMASK, + common.statFollowLinks(`${TMP}/chmod/file1`).mode & BITMASK, parseInt('755', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & BITMASK, + common.statFollowLinks(`${TMP}/chmod/file1`).mode & BITMASK, parseInt('644', 8) ); }); @@ -53,7 +54,7 @@ test('symbolic mode', t => { let result = shell.chmod('o+x', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('007', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('007', 8), parseInt('005', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -66,7 +67,7 @@ test('symbolic mode, without group', t => { let result = shell.chmod('+x', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & BITMASK, + common.statFollowLinks(`${TMP}/chmod/file1`).mode & BITMASK, parseInt('755', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -79,13 +80,13 @@ test('Test setuid', t => { let result = shell.chmod('u+s', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('4000', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('4000', 8), parseInt('4000', 8) ); result = shell.chmod('u-s', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & BITMASK, + common.statFollowLinks(`${TMP}/chmod/file1`).mode & BITMASK, parseInt('644', 8) ); @@ -97,7 +98,7 @@ test('Test setuid', t => { result = shell.chmod('755', `${TMP}/chmod/c`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/c`).mode & parseInt('4000', 8), + common.statFollowLinks(`${TMP}/chmod/c`).mode & parseInt('4000', 8), parseInt('4000', 8) ); result = shell.chmod('u-s', `${TMP}/chmod/c`); @@ -110,13 +111,13 @@ test('Test setgid', t => { let result = shell.chmod('g+s', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('2000', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('2000', 8), parseInt('2000', 8) ); result = shell.chmod('g-s', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & BITMASK, + common.statFollowLinks(`${TMP}/chmod/file1`).mode & BITMASK, parseInt('644', 8) ); }); @@ -127,16 +128,16 @@ test('Test sticky bit', t => { let result = shell.chmod('+t', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('1000', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('1000', 8), parseInt('1000', 8) ); result = shell.chmod('-t', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & BITMASK, + common.statFollowLinks(`${TMP}/chmod/file1`).mode & BITMASK, parseInt('644', 8) ); - t.is(fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('1000', 8), 0); + t.is(common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('1000', 8), 0); }); }); @@ -145,7 +146,7 @@ test('Test directories', t => { let result = shell.chmod('a-w', `${TMP}/chmod/b/a/b`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/b/a/b`).mode & BITMASK, + common.statFollowLinks(`${TMP}/chmod/b/a/b`).mode & BITMASK, parseInt('555', 8) ); result = shell.chmod('755', `${TMP}/chmod/b/a/b`); @@ -158,13 +159,13 @@ test('Test recursion', t => { let result = shell.chmod('-R', 'a+w', `${TMP}/chmod/b`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/b/a/b`).mode & BITMASK, + common.statFollowLinks(`${TMP}/chmod/b/a/b`).mode & BITMASK, BITMASK ); result = shell.chmod('-R', '755', `${TMP}/chmod/b`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/b/a/b`).mode & BITMASK, + common.statFollowLinks(`${TMP}/chmod/b/a/b`).mode & BITMASK, parseInt('755', 8) ); }); @@ -176,11 +177,11 @@ test('Test symbolic links w/ recursion - WARNING: *nix only', t => { let result = shell.chmod('-R', 'u-w', `${TMP}/chmod/a/b`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/a/b/c`).mode & parseInt('700', 8), + common.statFollowLinks(`${TMP}/chmod/a/b/c`).mode & parseInt('700', 8), parseInt('500', 8) ); t.is( - fs.statSync(`${TMP}/chmod/b/a`).mode & parseInt('700', 8), + common.statFollowLinks(`${TMP}/chmod/b/a`).mode & parseInt('700', 8), parseInt('700', 8) ); result = shell.chmod('-R', 'u+w', `${TMP}/chmod/a/b`); @@ -193,7 +194,7 @@ test('Test combinations', t => { let result = shell.chmod('a-rwx', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('000', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('000', 8), parseInt('000', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -204,7 +205,7 @@ test('multiple symbolic modes', t => { let result = shell.chmod('a-rwx,u+r', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('400', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('400', 8), parseInt('400', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -215,7 +216,7 @@ test('multiple symbolic modes #2', t => { let result = shell.chmod('a-rwx,u+rw', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('600', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('600', 8), parseInt('600', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -227,7 +228,7 @@ test('multiple symbolic modes #3', t => { let result = shell.chmod('a-rwx,u+rwx', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('700', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('700', 8), parseInt('700', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -241,7 +242,7 @@ test('u+rw', t => { result = shell.chmod('u+rw', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('600', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('600', 8), parseInt('600', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -255,7 +256,7 @@ test('u+wx', t => { result = shell.chmod('u+wx', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('300', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('300', 8), parseInt('300', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -270,7 +271,7 @@ test('Multiple symbolic modes at once', t => { result = shell.chmod('u+r,g+w,o+x', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('421', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('421', 8), parseInt('421', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -285,7 +286,7 @@ test('u+rw,g+wx', t => { result = shell.chmod('u+rw,g+wx', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('630', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('630', 8), parseInt('630', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -299,7 +300,7 @@ test('u-x,g+rw', t => { result = shell.chmod('u-x,g+rw', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('660', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('660', 8), parseInt('660', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -310,13 +311,13 @@ test('a-rwx,u+rw', t => { let result = shell.chmod('a-rwx,u+rw', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('600', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('600', 8), parseInt('600', 8) ); result = shell.chmod('a-rwx,u+rw', `${TMP}/chmod/file1`); t.is(result.code, 0); t.is( - fs.statSync(`${TMP}/chmod/file1`).mode & parseInt('600', 8), + common.statFollowLinks(`${TMP}/chmod/file1`).mode & parseInt('600', 8), parseInt('600', 8) ); result = shell.chmod('644', `${TMP}/chmod/file1`); @@ -339,19 +340,19 @@ test('Numeric modes', t => { test('Make sure chmod succeeds for a variety of octal codes', t => { utils.skipOnWin(t, () => { t.is( - fs.statSync(`${TMP}/chmod/xdir`).mode & parseInt('755', 8), + common.statFollowLinks(`${TMP}/chmod/xdir`).mode & parseInt('755', 8), parseInt('755', 8) ); t.is( - fs.statSync(`${TMP}/chmod/xdir/file`).mode & parseInt('644', 8), + common.statFollowLinks(`${TMP}/chmod/xdir/file`).mode & parseInt('644', 8), parseInt('644', 8) ); t.is( - fs.statSync(`${TMP}/chmod/xdir/deep`).mode & parseInt('755', 8), + common.statFollowLinks(`${TMP}/chmod/xdir/deep`).mode & parseInt('755', 8), parseInt('755', 8) ); t.is( - fs.statSync(`${TMP}/chmod/xdir/deep/file`).mode & parseInt('644', 8), + common.statFollowLinks(`${TMP}/chmod/xdir/deep/file`).mode & parseInt('644', 8), parseInt('644', 8) ); }); diff --git a/test/cp.js b/test/cp.js index 34b81c7e9..8ada327ad 100644 --- a/test/cp.js +++ b/test/cp.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import common from '../src/common'; import utils from './utils/utils'; const oldMaxDepth = shell.config.maxdepth; @@ -295,7 +296,7 @@ test( t.falsy(result.stderr); t.is(result.code, 0); t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`)); - t.falsy(fs.statSync(`${t.context.tmp}/file1.txt`).isDirectory()); // don't let it be a dir + t.falsy(common.statFollowLinks(`${t.context.tmp}/file1.txt`).isDirectory()); // don't let it be a dir } ); @@ -309,8 +310,8 @@ test('recursive, everything exists, no force flag', t => { test('-R implies to not follow links', t => { utils.skipOnWin(t, () => { shell.cp('-R', 'test/resources/cp/*', t.context.tmp); - t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link - t.falsy((fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink())); // this one isn't + t.truthy(common.statNoFollowLinks(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link + t.falsy((common.statNoFollowLinks(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink())); // this one isn't t.not( shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(), shell.cat(`${t.context.tmp}/fakeLinks/sym.lnk`).toString() @@ -319,8 +320,8 @@ test('-R implies to not follow links', t => { t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); - t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link - t.truthy(fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink()); // this one is now a link + t.truthy(common.statNoFollowLinks(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link + t.truthy(common.statNoFollowLinks(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink()); // this one is now a link t.is( shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(), shell.cat(`${t.context.tmp}/fakeLinks/sym.lnk`).toString() @@ -333,8 +334,8 @@ test('Missing -R implies -L', t => { // Recursive, everything exists, overwrite a real file *by following a link* // Because missing the -R implies -L. shell.cp('-R', 'test/resources/cp/*', t.context.tmp); - t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link - t.falsy((fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink())); // this one isn't + t.truthy(common.statNoFollowLinks(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link + t.falsy((common.statNoFollowLinks(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink())); // this one isn't t.not( shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(), shell.cat(`${t.context.tmp}/fakeLinks/sym.lnk`).toString() @@ -343,8 +344,8 @@ test('Missing -R implies -L', t => { t.falsy(shell.error()); t.falsy(result.stderr); t.is(result.code, 0); - t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link - t.falsy(fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink()); // this one is still not a link + t.truthy(common.statNoFollowLinks(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink()); // this one is still not a link // But it still follows the link t.is( shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(), @@ -414,11 +415,11 @@ test( utils.skipOnWin(t, () => { // preserve mode bits const execBit = parseInt('001', 8); - t.is(fs.statSync('test/resources/cp-mode-bits/executable').mode & execBit, execBit); + t.is(common.statFollowLinks('test/resources/cp-mode-bits/executable').mode & execBit, execBit); shell.cp('test/resources/cp-mode-bits/executable', `${t.context.tmp}/executable`); t.is( - fs.statSync('test/resources/cp-mode-bits/executable').mode, - fs.statSync(`${t.context.tmp}/executable`).mode + common.statFollowLinks('test/resources/cp-mode-bits/executable').mode, + common.statFollowLinks(`${t.context.tmp}/executable`).mode ); }); } @@ -459,29 +460,29 @@ test('no-recursive will copy regular files only', t => { test('-R implies -P', t => { utils.skipOnWin(t, () => { shell.cp('-R', 'test/resources/cp/links/sym.lnk', t.context.tmp); - t.truthy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); + t.truthy(common.statNoFollowLinks(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); }); test('using -P explicitly works', t => { utils.skipOnWin(t, () => { shell.cp('-P', 'test/resources/cp/links/sym.lnk', t.context.tmp); - t.truthy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); + t.truthy(common.statNoFollowLinks(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); }); test('using -PR on a link to a folder does not follow the link', t => { utils.skipOnWin(t, () => { shell.cp('-PR', 'test/resources/cp/symFolder', t.context.tmp); - t.truthy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink()); + t.truthy(common.statNoFollowLinks(`${t.context.tmp}/symFolder`).isSymbolicLink()); }); }); test('-L overrides -P for copying directory', t => { utils.skipOnWin(t, () => { shell.cp('-LPR', 'test/resources/cp/symFolder', t.context.tmp); - t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink()); - t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder/sym.lnk`).isSymbolicLink()); + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/symFolder`).isSymbolicLink()); + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/symFolder/sym.lnk`).isSymbolicLink()); }); }); @@ -537,34 +538,34 @@ test('-u flag works correctly recursively', t => { test('using -R on a link to a folder *does* follow the link', t => { shell.cp('-R', 'test/resources/cp/symFolder', t.context.tmp); - t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink()); + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/symFolder`).isSymbolicLink()); }); test('Without -R, -L is implied', t => { shell.cp('test/resources/cp/links/sym.lnk', t.context.tmp); - t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); test('-L explicitly works', t => { shell.cp('-L', 'test/resources/cp/links/sym.lnk', t.context.tmp); - t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); test('using -LR does not imply -P', t => { shell.cp('-LR', 'test/resources/cp/links/sym.lnk', t.context.tmp); - t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); test('using -LR also works recursively on directories containing links', t => { shell.cp('-LR', 'test/resources/cp/links', t.context.tmp); - t.falsy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); }); test('-L always overrides a -P', t => { shell.cp('-LP', 'test/resources/cp/links/sym.lnk', t.context.tmp); - t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); shell.cp('-LPR', 'test/resources/cp/links/sym.lnk', t.context.tmp); - t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); + t.falsy(common.statNoFollowLinks(`${t.context.tmp}/sym.lnk`).isSymbolicLink()); }); test('Make sure max depth does not limit shallow directory structures', t => { diff --git a/test/head.js b/test/head.js index 9d85aca6a..51b812686 100644 --- a/test/head.js +++ b/test/head.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import common from '../src/common'; shell.config.silent = true; @@ -25,7 +26,7 @@ test('file does not exist', t => { }); test('directory', t => { - t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + t.truthy(common.statFollowLinks('test/resources/').isDirectory()); // sanity check const result = shell.head('test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); diff --git a/test/ls.js b/test/ls.js index 2cdc1933c..0163f6f73 100644 --- a/test/ls.js +++ b/test/ls.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import common from '../src/common'; import utils from './utils/utils'; const CWD = process.cwd(); @@ -463,7 +464,7 @@ test('long option, directory, recursive (and windows converts slashes)', t => { t.truthy(idx >= 0); result = result[idx]; t.is(result.name, result.name); - t.truthy(fs.statSync('test/resources/ls/a_dir/b_dir').isDirectory()); + t.truthy(common.statFollowLinks('test/resources/ls/a_dir/b_dir').isDirectory()); t.is(typeof result.nlink, 'number'); // This can vary between the local machine and travis t.is(typeof result.size, 'number'); // This can vary between different file systems t.truthy(result.mode); // check that these keys exist diff --git a/test/mkdir.js b/test/mkdir.js index 3827c2d38..5e5e75a0e 100644 --- a/test/mkdir.js +++ b/test/mkdir.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import common from '../src/common'; import utils from './utils/utils'; test.beforeEach(t => { @@ -28,21 +29,21 @@ test('no args', t => { }); test('dir already exists', t => { - const mtime = fs.statSync(t.context.tmp).mtime.toString(); + const mtime = common.statFollowLinks(t.context.tmp).mtime.toString(); const result = shell.mkdir(t.context.tmp); // dir already exists t.truthy(shell.error()); t.is(result.code, 1); t.is(result.stderr, `mkdir: path already exists: ${t.context.tmp}`); - t.is(fs.statSync(t.context.tmp).mtime.toString(), mtime); // didn't mess with dir + t.is(common.statFollowLinks(t.context.tmp).mtime.toString(), mtime); // didn't mess with dir }); test('Can\'t overwrite a broken link', t => { - const mtime = fs.lstatSync('test/resources/badlink').mtime.toString(); + const mtime = common.statNoFollowLinks('test/resources/badlink').mtime.toString(); const result = shell.mkdir('test/resources/badlink'); t.truthy(shell.error()); t.is(result.code, 1); t.is(result.stderr, 'mkdir: path already exists: test/resources/badlink'); - t.is(fs.lstatSync('test/resources/badlink').mtime.toString(), mtime); // didn't mess with file + t.is(common.statNoFollowLinks('test/resources/badlink').mtime.toString(), mtime); // didn't mess with file }); test('root path does not exist', t => { @@ -56,30 +57,30 @@ test('root path does not exist', t => { }); test('try to overwrite file', t => { - t.truthy(fs.statSync('test/resources/file1').isFile()); + t.truthy(common.statFollowLinks('test/resources/file1').isFile()); const result = shell.mkdir('test/resources/file1'); t.truthy(shell.error()); t.is(result.code, 1); t.is(result.stderr, 'mkdir: path already exists: test/resources/file1'); - t.truthy(fs.statSync('test/resources/file1').isFile()); + t.truthy(common.statFollowLinks('test/resources/file1').isFile()); }); test('try to overwrite file, with -p', t => { - t.truthy(fs.statSync('test/resources/file1').isFile()); + t.truthy(common.statFollowLinks('test/resources/file1').isFile()); const result = shell.mkdir('-p', 'test/resources/file1'); t.truthy(shell.error()); t.is(result.code, 1); t.is(result.stderr, 'mkdir: cannot create directory test/resources/file1: File exists'); - t.truthy(fs.statSync('test/resources/file1').isFile()); + t.truthy(common.statFollowLinks('test/resources/file1').isFile()); }); test('try to make a subdirectory of a file', t => { - t.truthy(fs.statSync('test/resources/file1').isFile()); + t.truthy(common.statFollowLinks('test/resources/file1').isFile()); const result = shell.mkdir('test/resources/file1/subdir'); t.truthy(shell.error()); t.is(result.code, 1); t.is(result.stderr, 'mkdir: cannot create directory test/resources/file1/subdir: Not a directory'); - t.truthy(fs.statSync('test/resources/file1').isFile()); + t.truthy(common.statFollowLinks('test/resources/file1').isFile()); t.falsy(fs.existsSync('test/resources/file1/subdir')); }); diff --git a/test/sort.js b/test/sort.js index 6d28c1e25..82015e41c 100644 --- a/test/sort.js +++ b/test/sort.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import common from '../src/common'; shell.config.silent = true; @@ -31,7 +32,7 @@ test('file does not exist', t => { }); test('directory', t => { - t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + t.truthy(common.statFollowLinks('test/resources/').isDirectory()); // sanity check const result = shell.sort('test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); diff --git a/test/tail.js b/test/tail.js index 328fb22ff..0942aabf8 100644 --- a/test/tail.js +++ b/test/tail.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import common from '../src/common'; shell.config.silent = true; @@ -24,7 +25,7 @@ test('file does not exist', t => { }); test('directory', t => { - t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + t.truthy(common.statFollowLinks('test/resources/').isDirectory()); // sanity check const result = shell.tail('test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); diff --git a/test/touch.js b/test/touch.js index 0221170f5..41b2107b1 100644 --- a/test/touch.js +++ b/test/touch.js @@ -4,6 +4,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import common from '../src/common'; import utils from './utils/utils'; test.beforeEach(t => { @@ -21,7 +22,7 @@ function resetUtimes(f) { const d = new Date(); d.setYear(2000); fs.utimesSync(f, d, d); - return fs.statSync(f); + return common.statFollowLinks(f); } function tmpFile(t, noCreate) { @@ -98,23 +99,23 @@ test('uses a reference file for mtime', t => { t.falsy(shell.error()); t.is(result.code, 0); t.not( - fs.statSync(testFile).mtime.getTime(), - fs.statSync(testFile2).mtime.getTime() + common.statFollowLinks(testFile).mtime.getTime(), + common.statFollowLinks(testFile2).mtime.getTime() ); t.not( - fs.statSync(testFile).atime.getTime(), - fs.statSync(testFile2).atime.getTime() + common.statFollowLinks(testFile).atime.getTime(), + common.statFollowLinks(testFile2).atime.getTime() ); result = shell.touch({ '-r': testFile2 }, testFile); t.falsy(shell.error()); t.is(result.code, 0); t.is( - fs.statSync(testFile).mtime.getTime(), - fs.statSync(testFile2).mtime.getTime() + common.statFollowLinks(testFile).mtime.getTime(), + common.statFollowLinks(testFile2).mtime.getTime() ); t.is( - fs.statSync(testFile).atime.getTime(), - fs.statSync(testFile2).atime.getTime() + common.statFollowLinks(testFile).atime.getTime(), + common.statFollowLinks(testFile2).atime.getTime() ); }); @@ -123,8 +124,8 @@ test('sets mtime and atime by default', t => { const oldStat = resetUtimes(testFile); const result = shell.touch(testFile); t.is(result.code, 0); - t.truthy(oldStat.mtime < fs.statSync(testFile).mtime); - t.truthy(oldStat.atime < fs.statSync(testFile).atime); + t.truthy(oldStat.mtime < common.statFollowLinks(testFile).mtime); + t.truthy(oldStat.atime < common.statFollowLinks(testFile).atime); }); test('does not set mtime if told not to', t => { @@ -132,7 +133,7 @@ test('does not set mtime if told not to', t => { const oldStat = resetUtimes(testFile); const result = shell.touch('-a', testFile); t.is(result.code, 0); - t.is(oldStat.mtime.getTime(), fs.statSync(testFile).mtime.getTime()); + t.is(oldStat.mtime.getTime(), common.statFollowLinks(testFile).mtime.getTime()); }); test('does not set atime if told not to', t => { @@ -140,7 +141,7 @@ test('does not set atime if told not to', t => { const oldStat = resetUtimes(testFile); const result = shell.touch('-m', testFile); t.is(result.code, 0); - t.is(oldStat.atime.getTime(), fs.statSync(testFile).atime.getTime()); + t.is(oldStat.atime.getTime(), common.statFollowLinks(testFile).atime.getTime()); }); test('multiple files', t => { diff --git a/test/uniq.js b/test/uniq.js index c85df4e27..51881ff90 100644 --- a/test/uniq.js +++ b/test/uniq.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import common from '../src/common'; shell.config.silent = true; @@ -24,7 +25,7 @@ test('file does not exist', t => { }); test('directory', t => { - t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + t.truthy(common.statFollowLinks('test/resources/').isDirectory()); // sanity check const result = shell.uniq('test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); @@ -32,7 +33,7 @@ test('directory', t => { }); test('output directory', t => { - t.truthy(fs.statSync('test/resources/').isDirectory()); // sanity check + t.truthy(common.statFollowLinks('test/resources/').isDirectory()); // sanity check const result = shell.uniq('test/resources/file1.txt', 'test/resources/'); t.truthy(shell.error()); t.is(result.code, 1); From 9e3f9abd2a2b66cae800783d62fb43b0122ea51f Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 19 Oct 2017 13:19:52 -0700 Subject: [PATCH 24/71] refactor(exec): move child process to source file (#786) This PR refactors `shell.exec()` by putting its child process in a separate code file. This also slightly cleans up dead code. There's more potential to clean this up (e.g. exit status), but this is a good enough start. Issue #782 --- src/exec-child.js | 46 ++++++++++++++++++++++++++++ src/exec.js | 76 ++++++++++++++++++----------------------------- test/exec.js | 6 ++++ 3 files changed, 81 insertions(+), 47 deletions(-) create mode 100644 src/exec-child.js diff --git a/src/exec-child.js b/src/exec-child.js new file mode 100644 index 000000000..cd47597e6 --- /dev/null +++ b/src/exec-child.js @@ -0,0 +1,46 @@ +if (require.main !== module) { + throw new Error('This file should not be required'); +} + +var childProcess = require('child_process'); +var fs = require('fs'); + +// Note: this will break if `paramFilePath` contains special characters ( '\n', +// '\t', etc.). Such characters are possible if $TMP gets modified. We already +// rely on tempdir() to work for other things, so this is an acceptable risk. +var paramFilePath = process.argv[2]; + +var serializedParams = fs.readFileSync(paramFilePath, 'utf8'); +var params = JSON.parse(serializedParams); + +var cmd = params.command; +var execOptions = params.execOptions; +var pipe = params.pipe; +var stdoutFile = params.stdoutFile; +var stderrFile = params.stderrFile; +var codeFile = params.codeFile; + +var c = childProcess.exec(cmd, execOptions, function (err) { + if (!err) { + fs.writeFileSync(codeFile, '0'); + } else if (err.code === undefined) { + fs.writeFileSync(codeFile, '1'); + } else { + fs.writeFileSync(codeFile, err.code.toString()); + } +}); + +var stdoutStream = fs.createWriteStream(stdoutFile); +var stderrStream = fs.createWriteStream(stderrFile); + +c.stdout.pipe(stdoutStream, { end: false }); +c.stderr.pipe(stderrStream, { end: false }); +c.stdout.pipe(process.stdout); +c.stderr.pipe(process.stderr); + +if (pipe) { + c.stdin.end(pipe); +} + +c.stdout.on('end', stdoutStream.end); +c.stderr.on('end', stderrStream.end); diff --git a/src/exec.js b/src/exec.js index d425b5b21..936b36b7b 100644 --- a/src/exec.js +++ b/src/exec.js @@ -24,10 +24,10 @@ function execSync(cmd, opts, pipe) { } var tempDir = _tempDir(); - var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName()); - var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); var codeFile = path.resolve(tempDir + '/' + common.randomFileName()); - var scriptFile = path.resolve(tempDir + '/' + common.randomFileName()); + var paramsFile = path.resolve(tempDir + '/' + common.randomFileName()); + var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); + var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName()); opts = common.extend({ silent: common.config.silent, @@ -37,47 +37,29 @@ function execSync(cmd, opts, pipe) { encoding: 'utf8', }, opts); - if (fs.existsSync(scriptFile)) common.unlinkSync(scriptFile); - if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile); - if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); if (fs.existsSync(codeFile)) common.unlinkSync(codeFile); - - var execCommand = JSON.stringify(common.config.execPath) + ' ' + JSON.stringify(scriptFile); - var script; + if (fs.existsSync(paramsFile)) common.unlinkSync(paramsFile); + if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); + if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile); opts.cwd = path.resolve(opts.cwd); - var optString = JSON.stringify(opts); - - script = [ - "var child = require('child_process')", - " , fs = require('fs');", - 'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {', - ' var fname = ' + JSON.stringify(codeFile) + ';', - ' if (!err) {', - ' fs.writeFileSync(fname, "0");', - ' } else if (err.code === undefined) {', - ' fs.writeFileSync(fname, "1");', - ' } else {', - ' fs.writeFileSync(fname, err.code.toString());', - ' }', - '});', - 'var stdoutStream = fs.createWriteStream(' + JSON.stringify(stdoutFile) + ');', - 'var stderrStream = fs.createWriteStream(' + JSON.stringify(stderrFile) + ');', - 'childProcess.stdout.pipe(stdoutStream, {end: false});', - 'childProcess.stderr.pipe(stderrStream, {end: false});', - 'childProcess.stdout.pipe(process.stdout);', - 'childProcess.stderr.pipe(process.stderr);', - ].join('\n') + - (pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n') + - [ - 'var stdoutEnded = false, stderrEnded = false;', - 'function tryClosingStdout(){ if(stdoutEnded){ stdoutStream.end(); } }', - 'function tryClosingStderr(){ if(stderrEnded){ stderrStream.end(); } }', - "childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosingStdout(); });", - "childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });", - ].join('\n'); - - fs.writeFileSync(scriptFile, script); + + var paramsToSerialize = { + command: cmd, + execOptions: opts, + pipe: pipe, + stdoutFile: stdoutFile, + stderrFile: stderrFile, + codeFile: codeFile, + }; + + fs.writeFileSync(paramsFile, JSON.stringify(paramsToSerialize), 'utf8'); + + var execCommand = [ + JSON.stringify(common.config.execPath), + JSON.stringify(path.join(__dirname, 'exec-child.js')), + JSON.stringify(paramsFile), + ].join(' '); /* istanbul ignore else */ if (opts.silent) { @@ -91,10 +73,10 @@ function execSync(cmd, opts, pipe) { child.execSync(execCommand, opts); } catch (e) { // Clean up immediately if we have an exception - try { common.unlinkSync(scriptFile); } catch (e2) {} - try { common.unlinkSync(stdoutFile); } catch (e2) {} - try { common.unlinkSync(stderrFile); } catch (e2) {} try { common.unlinkSync(codeFile); } catch (e2) {} + try { common.unlinkSync(paramsFile); } catch (e2) {} + try { common.unlinkSync(stderrFile); } catch (e2) {} + try { common.unlinkSync(stdoutFile); } catch (e2) {} throw e; } @@ -118,10 +100,10 @@ function execSync(cmd, opts, pipe) { } // No biggie if we can't erase the files now -- they're in a temp dir anyway - try { common.unlinkSync(scriptFile); } catch (e) {} - try { common.unlinkSync(stdoutFile); } catch (e) {} - try { common.unlinkSync(stderrFile); } catch (e) {} try { common.unlinkSync(codeFile); } catch (e) {} + try { common.unlinkSync(paramsFile); } catch (e) {} + try { common.unlinkSync(stderrFile); } catch (e) {} + try { common.unlinkSync(stdoutFile); } catch (e) {} if (code !== 0) { common.error('', code, { continue: true }); diff --git a/test/exec.js b/test/exec.js index f2a1c00f3..cdd87a653 100644 --- a/test/exec.js +++ b/test/exec.js @@ -48,6 +48,12 @@ test('exec exits gracefully if we cannot find the execPath', t => { ); }); +test('cannot require exec-child.js', t => { + t.throws(() => { + require('../src/exec-child.js'); + }, /This file should not be required/); +}); + // // Valids // From 90165ba2f58ef73055368527c225e85e6065874f Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 19 Oct 2017 23:06:24 -0700 Subject: [PATCH 25/71] docs(changelog): updated by Nate Fischer [ci skip] --- CHANGELOG.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7427c2ab..a5cc21492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,56 @@ # Change Log +## [Unreleased](https://github.com/shelljs/shelljs/tree/HEAD) + +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.8...HEAD) + +**Closed issues:** + +- Is it possible to get a js library\(file\) for ShellJS [\#776](https://github.com/shelljs/shelljs/issues/776) +- 48, [\#774](https://github.com/shelljs/shelljs/issues/774) +- 47 [\#773](https://github.com/shelljs/shelljs/issues/773) +- getting different result from terminal and with shelljs [\#769](https://github.com/shelljs/shelljs/issues/769) +- test\(\) does not support -w and -x options [\#768](https://github.com/shelljs/shelljs/issues/768) +- Snyk "high severity" issue [\#766](https://github.com/shelljs/shelljs/issues/766) +- Snyk "high security [\#765](https://github.com/shelljs/shelljs/issues/765) +- Run second shell script [\#756](https://github.com/shelljs/shelljs/issues/756) +- shelljs seems NOT compatible with nexe under CentOS 6.5 [\#754](https://github.com/shelljs/shelljs/issues/754) +- Feature request: pushd/popd -q option [\#753](https://github.com/shelljs/shelljs/issues/753) +- cat doesn't support '-n' option [\#750](https://github.com/shelljs/shelljs/issues/750) +- shelljs run xcodebuild error [\#749](https://github.com/shelljs/shelljs/issues/749) +- Add wrappers around fs.statSync and fs.lstatSync [\#745](https://github.com/shelljs/shelljs/issues/745) +- Improve coverage for exec\(\) [\#742](https://github.com/shelljs/shelljs/issues/742) +- Improve coverage for head\(\) [\#741](https://github.com/shelljs/shelljs/issues/741) +- shelljs is no longer used in PDF.js [\#737](https://github.com/shelljs/shelljs/issues/737) +- ls doesn't follow links to directories [\#733](https://github.com/shelljs/shelljs/issues/733) +- Add test for `ls regular-file.txt` [\#732](https://github.com/shelljs/shelljs/issues/732) +- shelljs.exec hangs when password it's asked [\#716](https://github.com/shelljs/shelljs/issues/716) +- Clean up common tests [\#714](https://github.com/shelljs/shelljs/issues/714) +- Switch to os.homedir\(\) when we move to v4+ [\#683](https://github.com/shelljs/shelljs/issues/683) +- Can't run docker with exec\(\) \(the input device is not a TTY\) [\#680](https://github.com/shelljs/shelljs/issues/680) +- Cant get encoding buffer to work on exec [\#675](https://github.com/shelljs/shelljs/issues/675) +- Set up Codecov for the project [\#671](https://github.com/shelljs/shelljs/issues/671) +- ShellJS: internal error Error: EBUSY: resource busy or locked, lstat 'C:\pagefile.sys' [\#514](https://github.com/shelljs/shelljs/issues/514) +- Echo doesn't return value ending in a trailing newline [\#476](https://github.com/shelljs/shelljs/issues/476) + +**Merged pull requests:** + +- refactor\(exec\): move child process to source file [\#786](https://github.com/shelljs/shelljs/pull/786) ([nfischer](https://github.com/nfischer)) +- Remove unnecessary shell.error checks from common tests [\#785](https://github.com/shelljs/shelljs/pull/785) ([freitagbr](https://github.com/freitagbr)) +- Add a test for ls for a single file [\#784](https://github.com/shelljs/shelljs/pull/784) ([freitagbr](https://github.com/freitagbr)) +- Wrap fs.statSync and fs.lstatSync [\#783](https://github.com/shelljs/shelljs/pull/783) ([freitagbr](https://github.com/freitagbr)) +- chore: set AVA options [\#780](https://github.com/shelljs/shelljs/pull/780) ([nfischer](https://github.com/nfischer)) +- chore: clean up refs to unsupported node versions [\#779](https://github.com/shelljs/shelljs/pull/779) ([nfischer](https://github.com/nfischer)) +- Added `-q` \(quiet\) option to `push`, `popd`, `dirs` functions. [\#777](https://github.com/shelljs/shelljs/pull/777) ([alexreg](https://github.com/alexreg)) +- feat\(cat\): number output lines \(\#750\) [\#775](https://github.com/shelljs/shelljs/pull/775) ([gcca](https://github.com/gcca)) +- Fix ls not following links to directories by default [\#764](https://github.com/shelljs/shelljs/pull/764) ([freitagbr](https://github.com/freitagbr)) +- Add "encoding" option to exec [\#763](https://github.com/shelljs/shelljs/pull/763) ([freitagbr](https://github.com/freitagbr)) +- refactor\(test\): update AVA and refactor tests [\#760](https://github.com/shelljs/shelljs/pull/760) ([nfischer](https://github.com/nfischer)) +- chore: add skipOnWin and skipOnUnix test helpers [\#746](https://github.com/shelljs/shelljs/pull/746) ([nfischer](https://github.com/nfischer)) +- test\(exec\): add tests for coverage [\#744](https://github.com/shelljs/shelljs/pull/744) ([nfischer](https://github.com/nfischer)) +- test\(head\): improve coverage [\#743](https://github.com/shelljs/shelljs/pull/743) ([nfischer](https://github.com/nfischer)) +- Remove PDF.js mention from README.md [\#738](https://github.com/shelljs/shelljs/pull/738) ([voy](https://github.com/voy)) + ## [v0.7.8](https://github.com/shelljs/shelljs/tree/v0.7.8) (2017-06-07) [Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.7...v0.7.8) @@ -30,6 +81,7 @@ **Merged pull requests:** +- Merge dev into master [\#731](https://github.com/shelljs/shelljs/pull/731) ([freitagbr](https://github.com/freitagbr)) - Add node 8 to CI [\#730](https://github.com/shelljs/shelljs/pull/730) ([freitagbr](https://github.com/freitagbr)) - Deprecate common.getUserHome, advise using os.homedir instead [\#725](https://github.com/shelljs/shelljs/pull/725) ([freitagbr](https://github.com/freitagbr)) - fix\(mkdir\): improve error handling around files [\#721](https://github.com/shelljs/shelljs/pull/721) ([nfischer](https://github.com/nfischer)) From e9461dc5a7f9f8acf0bb21d23d6bd3ed9f2b23dc Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Mon, 23 Oct 2017 17:27:13 -0700 Subject: [PATCH 26/71] Add note to issue template about FAQ (#794) * Add note to issue template about FAQ * Use more general language in FAQ comment --- .github/ISSUE_TEMPLATE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 13d777fbc..172af387f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,3 +1,7 @@ + ### Node version (or tell us if you're using electron or some other framework): ### ShellJS version (the most recent version/Github branch you see the bug on): From b885590e0f005faa69ff10bd1b777367886df1ae Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 26 Oct 2017 20:33:04 -0700 Subject: [PATCH 27/71] Use execFileSync to launch child process (#790) This uses `child_process.execFileSync` instead of `execSync` to launch the child process. This further reduces the attack surface, removing a possible point for command injection in the ShellJS implementation. This does not affect backwards compatibility for the `shell.exec` API (the behavior is determined by the call to `child_process.exec` within `src/exec-child.js`). Issue #782 --- src/exec-child.js | 3 --- src/exec.js | 15 +++++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/exec-child.js b/src/exec-child.js index cd47597e6..798f31388 100644 --- a/src/exec-child.js +++ b/src/exec-child.js @@ -5,9 +5,6 @@ if (require.main !== module) { var childProcess = require('child_process'); var fs = require('fs'); -// Note: this will break if `paramFilePath` contains special characters ( '\n', -// '\t', etc.). Such characters are possible if $TMP gets modified. We already -// rely on tempdir() to work for other things, so this is an acceptable risk. var paramFilePath = process.argv[2]; var serializedParams = fs.readFileSync(paramFilePath, 'utf8'); diff --git a/src/exec.js b/src/exec.js index 936b36b7b..9a848e895 100644 --- a/src/exec.js +++ b/src/exec.js @@ -55,11 +55,10 @@ function execSync(cmd, opts, pipe) { fs.writeFileSync(paramsFile, JSON.stringify(paramsToSerialize), 'utf8'); - var execCommand = [ - JSON.stringify(common.config.execPath), - JSON.stringify(path.join(__dirname, 'exec-child.js')), - JSON.stringify(paramsFile), - ].join(' '); + var execArgs = [ + path.join(__dirname, 'exec-child.js'), + paramsFile, + ]; /* istanbul ignore else */ if (opts.silent) { @@ -70,7 +69,11 @@ function execSync(cmd, opts, pipe) { // Welcome to the future try { - child.execSync(execCommand, opts); + // Bad things if we pass in a `shell` option to child_process.execFileSync, + // so we need to explicitly remove it here. + delete opts.shell; + + child.execFileSync(common.config.execPath, execArgs, opts); } catch (e) { // Clean up immediately if we have an exception try { common.unlinkSync(codeFile); } catch (e2) {} From a187bd1b36ce28a5af214607257506ee28e1beb6 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 26 Oct 2017 21:29:26 -0700 Subject: [PATCH 28/71] Provide an API to pass parameters which resemble options (#792) This adds the special option string `--`, which means "no options". This can be passed if the first parameter looks like an option (starts with a `-` followed by 1+ letters). Fixes #778 --- README.md | 10 ++++++++++ src/common.js | 5 +++++ test/common.js | 12 ++++++++++++ test/grep.js | 6 ++++++ test/resources/grep/file2 | 3 +++ 5 files changed, 36 insertions(+) create mode 100644 test/resources/grep/file2 diff --git a/README.md b/README.md index 36087920e..169a5b9a1 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,16 @@ if (shell.exec('git commit -am "Auto-commit"').code !== 0) { } ``` +## Exclude options + +If you need to pass a parameter that looks like an option, you can do so like: + +```js +shell.grep('--', '-v', 'path/to/file'); // Search for "-v", no grep options + +shell.cp('-R', '-dir', 'outdir'); // If already using an option, you're done +``` + ## Global vs. Local We no longer recommend using a global-import for ShellJS (i.e. diff --git a/src/common.js b/src/common.js index 77e0306e4..7dad365a8 100644 --- a/src/common.js +++ b/src/common.js @@ -171,6 +171,11 @@ function parseOptions(opt, map, errorOptions) { throw new Error('parseOptions() internal error: errorOptions must be object'); } + if (opt === '--') { + // This means there are no options. + return {}; + } + // All options are false by default var options = {}; Object.keys(map).forEach(function (letter) { diff --git a/test/common.js b/test/common.js index b433f91ba..5e66c1b6c 100644 --- a/test/common.js +++ b/test/common.js @@ -264,6 +264,18 @@ test('common.parseOptions throws when passed a string not starting with "-"', t }, Error, "Options string must start with a '-'"); }); +test('common.parseOptions with -- argument', t => { + const result = common.parseOptions('--', { + R: 'recursive', + f: 'force', + r: 'reverse', + }); + + t.falsy(result.recursive); + t.falsy(result.force); + t.falsy(result.reverse); +}); + test('Some basic tests on the ShellString type', t => { const result = shell.ShellString('foo'); t.is(result.toString(), 'foo'); diff --git a/test/grep.js b/test/grep.js index 2fc62f50e..f450aabb1 100644 --- a/test/grep.js +++ b/test/grep.js @@ -136,3 +136,9 @@ test('-l option', t => { t.falsy(result.match(/file2.txt/)); t.is(result.split('\n').length - 1, 2); }); + +test('the pattern looks like an option', t => { + const result = shell.grep('--', '-v', 'test/resources/grep/file2'); + t.falsy(shell.error()); + t.is(result.toString(), '-v\n-vv\n'); +}); diff --git a/test/resources/grep/file2 b/test/resources/grep/file2 new file mode 100644 index 000000000..0c37715dc --- /dev/null +++ b/test/resources/grep/file2 @@ -0,0 +1,3 @@ +-v +-vv +-a From 8451fceb81abb252cba1144ff2a37362877b0079 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 30 Oct 2017 18:04:48 -0700 Subject: [PATCH 29/71] chore(eslint): use words instead of numbers (#797) Eslint rules can be configured either using words or number values: * "off" or 0 * "warn" or 1 * "error" or 2 This switches our config to use the string values instead of the number values, since the number values are too cryptic. No change to our actual settings. --- .eslintrc.json | 40 ++++++++++++++++++++-------------------- test/.eslintrc.json | 28 ++++++++++++++-------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index e712eeab2..7037c1760 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,26 +4,26 @@ }, "extends": "airbnb-base/legacy", "rules": { - "comma-dangle": [2, "always-multiline"], - "global-require": 0, - "vars-on-top": 0, - "spaced-comment": [2, "always", { "markers": ["@", "@include"], "exceptions": ["@", "@commands"] }], - "no-param-reassign": 0, - "no-console": 0, - "curly": [2, "multi-line"], - "func-names": 0, - "quote-props": 0, - "no-underscore-dangle": 0, - "max-len": 0, - "no-use-before-define": 0, - "no-empty": 0, - "no-else-return": 0, - "no-throw-literal": 0, - "newline-per-chained-call": 0, - "consistent-return": 0, - "no-mixed-operators": 0, - "no-prototype-builtins": 0, - "new-cap": [2, { + "comma-dangle": ["error", "always-multiline"], + "global-require": "off", + "vars-on-top": "off", + "spaced-comment": ["error", "always", { "markers": ["@", "@include"], "exceptions": ["@", "@commands"] }], + "no-param-reassign": "off", + "no-console": "off", + "curly": ["error", "multi-line"], + "func-names": "off", + "quote-props": "off", + "no-underscore-dangle": "off", + "max-len": "off", + "no-use-before-define": "off", + "no-empty": "off", + "no-else-return": "off", + "no-throw-literal": "off", + "newline-per-chained-call": "off", + "consistent-return": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "new-cap": ["error", { "capIsNewExceptions": [ "ShellString" ]} diff --git a/test/.eslintrc.json b/test/.eslintrc.json index fd8099cb3..6f23f8ec4 100644 --- a/test/.eslintrc.json +++ b/test/.eslintrc.json @@ -4,20 +4,20 @@ }, "extends": "airbnb-base", "rules": { - "import/no-mutable-exports": 0, - "global-require": 0, - "vars-on-top": 0, - "spaced-comment": [2, "always", { "markers": ["@", "@include"], "exceptions": ["@"] }], - "no-param-reassign": 0, - "no-console": 0, - "curly": 0, - "no-var": 2, - "prefer-const": 2, - "prefer-template": 0, - "prefer-arrow-callback": 0, - "no-underscore-dangle": 0, - "max-len": 0, - "new-cap": [2, { + "import/no-mutable-exports": "off", + "global-require": "off", + "vars-on-top": "off", + "spaced-comment": ["error", "always", { "markers": ["@", "@include"], "exceptions": ["@"] }], + "no-param-reassign": "off", + "no-console": "off", + "curly": "off", + "no-var": "error", + "prefer-const": "error", + "prefer-template": "off", + "prefer-arrow-callback": "off", + "no-underscore-dangle": "off", + "max-len": "off", + "new-cap": ["error", { "capIsNewExceptions": [ "ShellString" ]} From 6189d7f8e54456918520b469ec5074dd4c08875b Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 31 Oct 2017 15:51:18 -0700 Subject: [PATCH 30/71] Remove codeFile parameter (#791) This parameter isn't needed, we can easily rely on exit code status for this. Eliminating the parameter reduces file IO, code complexity, and removes a busy loop. This also removes some legacy code related to streams. Issue #782 --- src/exec-child.js | 14 +++++--------- src/exec.js | 28 ++++++---------------------- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/exec-child.js b/src/exec-child.js index 798f31388..eab86ed37 100644 --- a/src/exec-child.js +++ b/src/exec-child.js @@ -15,29 +15,25 @@ var execOptions = params.execOptions; var pipe = params.pipe; var stdoutFile = params.stdoutFile; var stderrFile = params.stderrFile; -var codeFile = params.codeFile; var c = childProcess.exec(cmd, execOptions, function (err) { if (!err) { - fs.writeFileSync(codeFile, '0'); + process.exitCode = 0; } else if (err.code === undefined) { - fs.writeFileSync(codeFile, '1'); + process.exitCode = 1; } else { - fs.writeFileSync(codeFile, err.code.toString()); + process.exitCode = err.code; } }); var stdoutStream = fs.createWriteStream(stdoutFile); var stderrStream = fs.createWriteStream(stderrFile); -c.stdout.pipe(stdoutStream, { end: false }); -c.stderr.pipe(stderrStream, { end: false }); +c.stdout.pipe(stdoutStream); +c.stderr.pipe(stderrStream); c.stdout.pipe(process.stdout); c.stderr.pipe(process.stderr); if (pipe) { c.stdin.end(pipe); } - -c.stdout.on('end', stdoutStream.end); -c.stderr.on('end', stderrStream.end); diff --git a/src/exec.js b/src/exec.js index 9a848e895..03f9826b5 100644 --- a/src/exec.js +++ b/src/exec.js @@ -13,18 +13,14 @@ common.register('exec', _exec, { wrapOutput: false, }); -// Hack to run child_process.exec() synchronously (sync avoids callback hell) -// Uses a custom wait loop that checks for a flag file, created when the child process is done. -// (Can't do a wait loop that checks for internal Node variables/messages as -// Node is single-threaded; callbacks and other internal state changes are done in the -// event loop). +// We use this function to run exec synchronously while also providing realtime +// output. function execSync(cmd, opts, pipe) { if (!common.config.execPath) { common.error('Unable to find a path to the node binary. Please manually set config.execPath'); } var tempDir = _tempDir(); - var codeFile = path.resolve(tempDir + '/' + common.randomFileName()); var paramsFile = path.resolve(tempDir + '/' + common.randomFileName()); var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName()); @@ -37,7 +33,6 @@ function execSync(cmd, opts, pipe) { encoding: 'utf8', }, opts); - if (fs.existsSync(codeFile)) common.unlinkSync(codeFile); if (fs.existsSync(paramsFile)) common.unlinkSync(paramsFile); if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile); @@ -50,7 +45,6 @@ function execSync(cmd, opts, pipe) { pipe: pipe, stdoutFile: stdoutFile, stderrFile: stderrFile, - codeFile: codeFile, }; fs.writeFileSync(paramsFile, JSON.stringify(paramsToSerialize), 'utf8'); @@ -67,6 +61,8 @@ function execSync(cmd, opts, pipe) { opts.stdio = [0, 1, 2]; } + var code = 0; + // Welcome to the future try { // Bad things if we pass in a `shell` option to child_process.execFileSync, @@ -75,19 +71,8 @@ function execSync(cmd, opts, pipe) { child.execFileSync(common.config.execPath, execArgs, opts); } catch (e) { - // Clean up immediately if we have an exception - try { common.unlinkSync(codeFile); } catch (e2) {} - try { common.unlinkSync(paramsFile); } catch (e2) {} - try { common.unlinkSync(stderrFile); } catch (e2) {} - try { common.unlinkSync(stdoutFile); } catch (e2) {} - throw e; - } - - // At this point codeFile exists, but it's not necessarily flushed yet. - // Keep reading it until it is. - var code = parseInt('', 10); - while (isNaN(code)) { - code = parseInt(fs.readFileSync(codeFile, 'utf8'), 10); + // Commands with non-zero exit code raise an exception. + code = e.status; } // fs.readFileSync uses buffer encoding by default, so call @@ -103,7 +88,6 @@ function execSync(cmd, opts, pipe) { } // No biggie if we can't erase the files now -- they're in a temp dir anyway - try { common.unlinkSync(codeFile); } catch (e) {} try { common.unlinkSync(paramsFile); } catch (e) {} try { common.unlinkSync(stderrFile); } catch (e) {} try { common.unlinkSync(stdoutFile); } catch (e) {} From 8ab0a3a3931b59215553730ad86adef8b21a0fa0 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 13 Nov 2017 22:55:41 -0800 Subject: [PATCH 31/71] chore: update nyc dependency (#805) This is to fix an issue related to the most recent node 8.x.y versions. Fixes #803 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eea927891..59cfa5292 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "eslint": "^2.0.0", "eslint-config-airbnb-base": "^3.0.0", "eslint-plugin-import": "^1.11.1", - "nyc": "^10.0.0", + "nyc": "^11.3.0", "shelljs-changelog": "^0.2.0", "shelljs-release": "^0.2.0", "shx": "^0.2.0", From 64d5899abc86dd7b7fa84455c0ce3551786c4b5b Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 16 Nov 2017 12:43:54 -0800 Subject: [PATCH 32/71] refactor(exec): remove paramsFile (#807) The `paramsFile` is obsolete now that we use `execFileSync()` for our internal implementation. Instead, we pass parameters to the child process directly as a single commandline parameter to reduce file I/O. Issue #782 --- src/exec-child.js | 5 +---- src/exec.js | 7 +------ 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/exec-child.js b/src/exec-child.js index eab86ed37..4859e0328 100644 --- a/src/exec-child.js +++ b/src/exec-child.js @@ -5,10 +5,7 @@ if (require.main !== module) { var childProcess = require('child_process'); var fs = require('fs'); -var paramFilePath = process.argv[2]; - -var serializedParams = fs.readFileSync(paramFilePath, 'utf8'); -var params = JSON.parse(serializedParams); +var params = JSON.parse(process.argv[2]); var cmd = params.command; var execOptions = params.execOptions; diff --git a/src/exec.js b/src/exec.js index 03f9826b5..ea5793488 100644 --- a/src/exec.js +++ b/src/exec.js @@ -21,7 +21,6 @@ function execSync(cmd, opts, pipe) { } var tempDir = _tempDir(); - var paramsFile = path.resolve(tempDir + '/' + common.randomFileName()); var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName()); @@ -33,7 +32,6 @@ function execSync(cmd, opts, pipe) { encoding: 'utf8', }, opts); - if (fs.existsSync(paramsFile)) common.unlinkSync(paramsFile); if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile); @@ -47,11 +45,9 @@ function execSync(cmd, opts, pipe) { stderrFile: stderrFile, }; - fs.writeFileSync(paramsFile, JSON.stringify(paramsToSerialize), 'utf8'); - var execArgs = [ path.join(__dirname, 'exec-child.js'), - paramsFile, + JSON.stringify(paramsToSerialize), ]; /* istanbul ignore else */ @@ -88,7 +84,6 @@ function execSync(cmd, opts, pipe) { } // No biggie if we can't erase the files now -- they're in a temp dir anyway - try { common.unlinkSync(paramsFile); } catch (e) {} try { common.unlinkSync(stderrFile); } catch (e) {} try { common.unlinkSync(stdoutFile); } catch (e) {} From a2343d0eabf904b7abbf8213876d8b7ae621d576 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 16 Nov 2017 12:44:51 -0800 Subject: [PATCH 33/71] refactor: harden plugins against unknown options (#804) This reworks the plugin API such that: - Unable to register a command with unknown wrap-options - `TypeError` raised for wrap-option type mistakes - Remove the `overWrite` option (it's unused, probably safest to not expose for now) - `cmdOptions` defaults to `null` instead of `false` for type consistency (no change to default behavior) - Move `pipeMethods` logic into `_register`, since it makes more sense there This is not expected to have any effect on existing plugins. --- src/common.js | 34 +++++++++++++++++++++++----------- test/plugin.js | 23 +++++++++++++++++++++-- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/common.js b/src/common.js index 7dad365a8..facd72fe1 100644 --- a/src/common.js +++ b/src/common.js @@ -52,9 +52,6 @@ exports.state = state; delete process.env.OLDPWD; // initially, there's no previous directory -// This is populated by calls to commonl.wrap() -var pipeMethods = []; - // Reliably test if something is any sort of javascript object function isObject(a) { return typeof a === 'object' && a !== null; @@ -315,9 +312,6 @@ exports.randomFileName = randomFileName; // command-logging, and other nice things function wrap(cmd, fn, options) { options = options || {}; - if (options.canReceivePipe) { - pipeMethods.push(cmd); - } return function () { var retValue = null; @@ -428,22 +422,36 @@ exports.readFromPipe = _readFromPipe; var DEFAULT_WRAP_OPTIONS = { allowGlobbing: true, canReceivePipe: false, - cmdOptions: false, + cmdOptions: null, globStart: 1, pipeOnly: false, - unix: true, wrapOutput: true, - overWrite: false, + unix: true, }; +// This is populated during plugin registration +var pipeMethods = []; + // Register a new ShellJS command function _register(name, implementation, wrapOptions) { wrapOptions = wrapOptions || {}; + + // Validate options + Object.keys(wrapOptions).forEach(function (option) { + if (!DEFAULT_WRAP_OPTIONS.hasOwnProperty(option)) { + throw new Error("Unknown option '" + option + "'"); + } + if (typeof wrapOptions[option] !== typeof DEFAULT_WRAP_OPTIONS[option]) { + throw new TypeError("Unsupported type '" + typeof wrapOptions[option] + + "' for option '" + option + "'"); + } + }); + // If an option isn't specified, use the default wrapOptions = Object.assign({}, DEFAULT_WRAP_OPTIONS, wrapOptions); - if (shell[name] && !wrapOptions.overWrite) { - throw new Error('unable to overwrite `' + name + '` command'); + if (shell[name]) { + throw new Error('Command `' + name + '` already exists'); } if (wrapOptions.pipeOnly) { @@ -452,5 +460,9 @@ function _register(name, implementation, wrapOptions) { } else { shell[name] = wrap(name, implementation, wrapOptions); } + + if (wrapOptions.canReceivePipe) { + pipeMethods.push(name); + } } exports.register = _register; diff --git a/test/plugin.js b/test/plugin.js index e8a2bbc4f..bafe2a050 100644 --- a/test/plugin.js +++ b/test/plugin.js @@ -39,6 +39,25 @@ test.beforeEach(() => { shell.config.resetForTesting(); }); +// +// Invalids +// + +test('Unable to register a plugin with unknown options', t => { + t.throws(() => { + plugin.register('foo', fooImplementation, { + foobar: true, + }); + }, Error); +}); + +test('Unable to register a plugin with wrong option types', t => { + t.throws(() => { + plugin.register('foo', fooImplementation, { + wrapOutput: 'true', // should be a boolean + }); + }, TypeError); +}); // // Valids @@ -139,10 +158,10 @@ test('Plugins can continue from errors', t => { t.is(shell.error(), 'foo: Error, but continuing'); }); -test('Cannot overwrite an existing command by default', t => { +test('Cannot overwrite an existing command', t => { const oldCat = shell.cat; t.throws(() => { plugin.register('cat', fooImplementation); - }, 'unable to overwrite `cat` command'); + }, 'Command `cat` already exists'); t.is(shell.cat, oldCat); }); From 0b65d2a06d3edf3bf4d60a20e744bffdd0f06d4a Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 11 Jan 2018 00:21:20 -0800 Subject: [PATCH 34/71] chore: update CI to Node v9 (#811) Fixes #799 --- .travis.yml | 1 + appveyor.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 90f780524..02a02fa5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ env: - NODE_VERSION="6" - NODE_VERSION="7" - NODE_VERSION="8" + - NODE_VERSION="9" # keep this blank to make sure there are no before_install steps before_install: diff --git a/appveyor.yml b/appveyor.yml index ad698e448..3c7952800 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,6 @@ environment: matrix: + - nodejs_version: '9' - nodejs_version: '8' - nodejs_version: '7' - nodejs_version: '6' From 8f8119cfae6e26d7bed39becaebf451cf49331dd Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 11 Jan 2018 21:12:42 -0800 Subject: [PATCH 35/71] docs: announce plugin API (#812) Fixes #391 --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 169a5b9a1..d5f577951 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,12 @@ $ shx touch foo/bar.txt $ shx rm -rf foo ``` +## Plugin API + +ShellJS now supports third-party plugins! You can learn more about using plugins +and writing your own ShellJS commands in [the +wiki](https://github.com/shelljs/shelljs/wiki/Using-ShellJS-Plugins). + ## A quick note about the docs For documentation on all the latest features, check out our From ec0d60aecf79513070786a1402b90c192ae1824e Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 11 Jan 2018 23:13:59 -0800 Subject: [PATCH 36/71] 0.8.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 59cfa5292..08076f63d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.7.8", + "version": "0.8.0", "description": "Portable Unix shell commands for Node.js", "keywords": [ "shelljs", From 902e49c0f81834c4da61ace740cc285417b3c5d3 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 11 Jan 2018 23:27:50 -0800 Subject: [PATCH 37/71] docs(changelog): updated by Nate Fischer [ci skip] --- CHANGELOG.md | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5cc21492..35171d608 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,23 @@ # Change Log -## [Unreleased](https://github.com/shelljs/shelljs/tree/HEAD) - -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.8...HEAD) +## [v0.8.0](https://github.com/shelljs/shelljs/tree/v0.8.0) (2018-01-12) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.8...v0.8.0) **Closed issues:** +- Snyk vulnerability DB reporting command injection vulnerability in ShellJS [\#810](https://github.com/shelljs/shelljs/issues/810) +- chore: upgrade nyc [\#803](https://github.com/shelljs/shelljs/issues/803) +- Update CI to use Node v9 [\#799](https://github.com/shelljs/shelljs/issues/799) +- Link to FAQ wiki section in our issue template [\#787](https://github.com/shelljs/shelljs/issues/787) - Is it possible to get a js library\(file\) for ShellJS [\#776](https://github.com/shelljs/shelljs/issues/776) - 48, [\#774](https://github.com/shelljs/shelljs/issues/774) - 47 [\#773](https://github.com/shelljs/shelljs/issues/773) +- Exec function calls JSON.stringify on command [\#772](https://github.com/shelljs/shelljs/issues/772) - getting different result from terminal and with shelljs [\#769](https://github.com/shelljs/shelljs/issues/769) - test\(\) does not support -w and -x options [\#768](https://github.com/shelljs/shelljs/issues/768) - Snyk "high severity" issue [\#766](https://github.com/shelljs/shelljs/issues/766) - Snyk "high security [\#765](https://github.com/shelljs/shelljs/issues/765) +- ShellJS doesn't respect NPM Registry being set outside of it [\#761](https://github.com/shelljs/shelljs/issues/761) - Run second shell script [\#756](https://github.com/shelljs/shelljs/issues/756) - shelljs seems NOT compatible with nexe under CentOS 6.5 [\#754](https://github.com/shelljs/shelljs/issues/754) - Feature request: pushd/popd -q option [\#753](https://github.com/shelljs/shelljs/issues/753) @@ -26,15 +31,29 @@ - Add test for `ls regular-file.txt` [\#732](https://github.com/shelljs/shelljs/issues/732) - shelljs.exec hangs when password it's asked [\#716](https://github.com/shelljs/shelljs/issues/716) - Clean up common tests [\#714](https://github.com/shelljs/shelljs/issues/714) -- Switch to os.homedir\(\) when we move to v4+ [\#683](https://github.com/shelljs/shelljs/issues/683) - Can't run docker with exec\(\) \(the input device is not a TTY\) [\#680](https://github.com/shelljs/shelljs/issues/680) - Cant get encoding buffer to work on exec [\#675](https://github.com/shelljs/shelljs/issues/675) - Set up Codecov for the project [\#671](https://github.com/shelljs/shelljs/issues/671) - ShellJS: internal error Error: EBUSY: resource busy or locked, lstat 'C:\pagefile.sys' [\#514](https://github.com/shelljs/shelljs/issues/514) +- Feature request: provide a way to skip option parsing [\#778](https://github.com/shelljs/shelljs/issues/778) +- Switch to os.homedir\(\) when we move to v4+ [\#683](https://github.com/shelljs/shelljs/issues/683) +- Drop support for v0.12 [\#647](https://github.com/shelljs/shelljs/issues/647) +- feature: echo -n [\#559](https://github.com/shelljs/shelljs/issues/559) +- Don't kill the node process upon unexpected error [\#483](https://github.com/shelljs/shelljs/issues/483) - Echo doesn't return value ending in a trailing newline [\#476](https://github.com/shelljs/shelljs/issues/476) +- Synchronous exec stalls permenantly when there is an error/w the shell [\#7](https://github.com/shelljs/shelljs/issues/7) **Merged pull requests:** +- docs: announce plugin API [\#812](https://github.com/shelljs/shelljs/pull/812) ([nfischer](https://github.com/nfischer)) +- chore: update CI to Node v9 [\#811](https://github.com/shelljs/shelljs/pull/811) ([nfischer](https://github.com/nfischer)) +- refactor\(exec\): remove paramsFile [\#807](https://github.com/shelljs/shelljs/pull/807) ([nfischer](https://github.com/nfischer)) +- chore: update nyc dependency [\#805](https://github.com/shelljs/shelljs/pull/805) ([nfischer](https://github.com/nfischer)) +- refactor: harden plugins against unknown options [\#804](https://github.com/shelljs/shelljs/pull/804) ([nfischer](https://github.com/nfischer)) +- chore\(eslint\): use words instead of numbers [\#797](https://github.com/shelljs/shelljs/pull/797) ([nfischer](https://github.com/nfischer)) +- Add note to issue template about FAQ [\#794](https://github.com/shelljs/shelljs/pull/794) ([freitagbr](https://github.com/freitagbr)) +- Remove codeFile parameter [\#791](https://github.com/shelljs/shelljs/pull/791) ([nfischer](https://github.com/nfischer)) +- Use execFileSync to launch child process [\#790](https://github.com/shelljs/shelljs/pull/790) ([nfischer](https://github.com/nfischer)) - refactor\(exec\): move child process to source file [\#786](https://github.com/shelljs/shelljs/pull/786) ([nfischer](https://github.com/nfischer)) - Remove unnecessary shell.error checks from common tests [\#785](https://github.com/shelljs/shelljs/pull/785) ([freitagbr](https://github.com/freitagbr)) - Add a test for ls for a single file [\#784](https://github.com/shelljs/shelljs/pull/784) ([freitagbr](https://github.com/freitagbr)) @@ -43,13 +62,19 @@ - chore: clean up refs to unsupported node versions [\#779](https://github.com/shelljs/shelljs/pull/779) ([nfischer](https://github.com/nfischer)) - Added `-q` \(quiet\) option to `push`, `popd`, `dirs` functions. [\#777](https://github.com/shelljs/shelljs/pull/777) ([alexreg](https://github.com/alexreg)) - feat\(cat\): number output lines \(\#750\) [\#775](https://github.com/shelljs/shelljs/pull/775) ([gcca](https://github.com/gcca)) -- Fix ls not following links to directories by default [\#764](https://github.com/shelljs/shelljs/pull/764) ([freitagbr](https://github.com/freitagbr)) -- Add "encoding" option to exec [\#763](https://github.com/shelljs/shelljs/pull/763) ([freitagbr](https://github.com/freitagbr)) - refactor\(test\): update AVA and refactor tests [\#760](https://github.com/shelljs/shelljs/pull/760) ([nfischer](https://github.com/nfischer)) - chore: add skipOnWin and skipOnUnix test helpers [\#746](https://github.com/shelljs/shelljs/pull/746) ([nfischer](https://github.com/nfischer)) - test\(exec\): add tests for coverage [\#744](https://github.com/shelljs/shelljs/pull/744) ([nfischer](https://github.com/nfischer)) - test\(head\): improve coverage [\#743](https://github.com/shelljs/shelljs/pull/743) ([nfischer](https://github.com/nfischer)) - Remove PDF.js mention from README.md [\#738](https://github.com/shelljs/shelljs/pull/738) ([voy](https://github.com/voy)) +- Provide an API to pass parameters which resemble options [\#792](https://github.com/shelljs/shelljs/pull/792) ([nfischer](https://github.com/nfischer)) +- Fix ls not following links to directories by default [\#764](https://github.com/shelljs/shelljs/pull/764) ([freitagbr](https://github.com/freitagbr)) +- Add "encoding" option to exec [\#763](https://github.com/shelljs/shelljs/pull/763) ([freitagbr](https://github.com/freitagbr)) +- Merge dev into master [\#731](https://github.com/shelljs/shelljs/pull/731) ([freitagbr](https://github.com/freitagbr)) +- Deprecate common.getUserHome, advise using os.homedir instead [\#725](https://github.com/shelljs/shelljs/pull/725) ([freitagbr](https://github.com/freitagbr)) +- Echo test mocks [\#708](https://github.com/shelljs/shelljs/pull/708) ([freitagbr](https://github.com/freitagbr)) +- Safely exit by throwing an error [\#546](https://github.com/shelljs/shelljs/pull/546) ([freitagbr](https://github.com/freitagbr)) +- chore\(make\): depreciate shelljs/make [\#431](https://github.com/shelljs/shelljs/pull/431) ([ariporad](https://github.com/ariporad)) ## [v0.7.8](https://github.com/shelljs/shelljs/tree/v0.7.8) (2017-06-07) [Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.7...v0.7.8) @@ -81,14 +106,11 @@ **Merged pull requests:** -- Merge dev into master [\#731](https://github.com/shelljs/shelljs/pull/731) ([freitagbr](https://github.com/freitagbr)) - Add node 8 to CI [\#730](https://github.com/shelljs/shelljs/pull/730) ([freitagbr](https://github.com/freitagbr)) -- Deprecate common.getUserHome, advise using os.homedir instead [\#725](https://github.com/shelljs/shelljs/pull/725) ([freitagbr](https://github.com/freitagbr)) - fix\(mkdir\): improve error handling around files [\#721](https://github.com/shelljs/shelljs/pull/721) ([nfischer](https://github.com/nfischer)) - Properly handle directories as arguments [\#713](https://github.com/shelljs/shelljs/pull/713) ([nfischer](https://github.com/nfischer)) - Add common.buffer [\#710](https://github.com/shelljs/shelljs/pull/710) ([freitagbr](https://github.com/freitagbr)) - Fix common.expand error [\#709](https://github.com/shelljs/shelljs/pull/709) ([freitagbr](https://github.com/freitagbr)) -- Echo test mocks [\#708](https://github.com/shelljs/shelljs/pull/708) ([freitagbr](https://github.com/freitagbr)) - refactor: remove unnecessary common.js imports [\#703](https://github.com/shelljs/shelljs/pull/703) ([nfischer](https://github.com/nfischer)) - Fix \#631 throw error when overwriting recently created file [\#702](https://github.com/shelljs/shelljs/pull/702) ([uttpal](https://github.com/uttpal)) - Small clarification of verbose flag [\#691](https://github.com/shelljs/shelljs/pull/691) ([zommerfelds](https://github.com/zommerfelds)) @@ -108,7 +130,6 @@ - Difference between bash ls -R and ShellJS ls -R with symlinks [\#666](https://github.com/shelljs/shelljs/issues/666) - Refactor which\(\) \(too many repeated code blocks\) [\#656](https://github.com/shelljs/shelljs/issues/656) - find\(\) raises error when unable to find any files matching, expected to return empty array. [\#653](https://github.com/shelljs/shelljs/issues/653) -- Drop support for v0.12 [\#647](https://github.com/shelljs/shelljs/issues/647) - Reformat the markdown in RELEASE.md [\#642](https://github.com/shelljs/shelljs/issues/642) - rm -rf doesn't work if the directory contains an asar archive in Electron [\#618](https://github.com/shelljs/shelljs/issues/618) - Add support for other file types in rm [\#617](https://github.com/shelljs/shelljs/issues/617) @@ -165,7 +186,6 @@ - write to file [\#568](https://github.com/shelljs/shelljs/issues/568) - Cannot figure out how to disable globbing for rm [\#567](https://github.com/shelljs/shelljs/issues/567) - Switch to the ava test framework [\#560](https://github.com/shelljs/shelljs/issues/560) -- feature: echo -n [\#559](https://github.com/shelljs/shelljs/issues/559) - Option not recognized [\#556](https://github.com/shelljs/shelljs/issues/556) - chore: add @freitagbr to LGTM maintainers [\#552](https://github.com/shelljs/shelljs/issues/552) - chore: set up dev branch [\#548](https://github.com/shelljs/shelljs/issues/548) @@ -179,7 +199,6 @@ - Feature request: allow `common.error\(\)` to optionally not insert a prefix and optionally not print to console [\#523](https://github.com/shelljs/shelljs/issues/523) - Feature request: Add "shelljs.unlink" [\#519](https://github.com/shelljs/shelljs/issues/519) - Sed should allow a replacement string to contain `\1` for match groups [\#507](https://github.com/shelljs/shelljs/issues/507) -- Don't kill the node process upon unexpected error [\#483](https://github.com/shelljs/shelljs/issues/483) - Usage with neodoc [\#445](https://github.com/shelljs/shelljs/issues/445) - \[ Feature idea \] synchronous sleep command [\#441](https://github.com/shelljs/shelljs/issues/441) - Improve test coverage [\#347](https://github.com/shelljs/shelljs/issues/347) @@ -249,7 +268,6 @@ - Add Brandon Freitag to maintainers/contributors [\#553](https://github.com/shelljs/shelljs/pull/553) ([freitagbr](https://github.com/freitagbr)) - Get pipe tests running on Windows. [\#550](https://github.com/shelljs/shelljs/pull/550) ([binki](https://github.com/binki)) - fix: maxdepth doesn't limit total number of copies [\#549](https://github.com/shelljs/shelljs/pull/549) ([nfischer](https://github.com/nfischer)) -- Safely exit by throwing an error [\#546](https://github.com/shelljs/shelljs/pull/546) ([freitagbr](https://github.com/freitagbr)) - Fix lint warning [\#543](https://github.com/shelljs/shelljs/pull/543) ([freitagbr](https://github.com/freitagbr)) - chore: remove v0.10 from Travis CI [\#540](https://github.com/shelljs/shelljs/pull/540) ([nfischer](https://github.com/nfischer)) - chore: add Node v7 for CI [\#539](https://github.com/shelljs/shelljs/pull/539) ([nfischer](https://github.com/nfischer)) @@ -270,7 +288,6 @@ - ShellJS in Electron package don't find ffmpeg anymore [\#516](https://github.com/shelljs/shelljs/issues/516) - Exec issues with string option introduced in 0.7.4 [\#515](https://github.com/shelljs/shelljs/issues/515) - \[ Feature \] SSH command [\#435](https://github.com/shelljs/shelljs/issues/435) -- Synchronous exec stalls permenantly when there is an error/w the shell [\#7](https://github.com/shelljs/shelljs/issues/7) **Merged pull requests:** @@ -372,7 +389,6 @@ - docs: comment code better to help contributors [\#437](https://github.com/shelljs/shelljs/pull/437) ([nfischer](https://github.com/nfischer)) - chore\(CI\): update appveyor [\#436](https://github.com/shelljs/shelljs/pull/436) ([nfischer](https://github.com/nfischer)) - chore: test against node v6 [\#433](https://github.com/shelljs/shelljs/pull/433) ([nfischer](https://github.com/nfischer)) -- chore\(make\): depreciate shelljs/make [\#431](https://github.com/shelljs/shelljs/pull/431) ([ariporad](https://github.com/ariporad)) - docs: warn that README contains newest features [\#410](https://github.com/shelljs/shelljs/pull/410) ([nfischer](https://github.com/nfischer)) ## [v0.7.0](https://github.com/shelljs/shelljs/tree/v0.7.0) (2016-04-25) @@ -631,7 +647,7 @@ - Breaking: Allow -- as args separators \(fixes \#188\) [\#207](https://github.com/shelljs/shelljs/pull/207) ([nzakas](https://github.com/nzakas)) - Update .travis.yml [\#190](https://github.com/shelljs/shelljs/pull/190) ([arturadib](https://github.com/arturadib)) -- Use new child\_process.execSync instead of busywaiting [\#189](https://github.com/shelljs/shelljs/pull/189) ([devTristan](https://github.com/devTristan)) +- Use new child\_process.execSync instead of busywaiting [\#189](https://github.com/shelljs/shelljs/pull/189) ([madd512](https://github.com/madd512)) - Update README.md: explains how to access "config" [\#145](https://github.com/shelljs/shelljs/pull/145) ([kerphi](https://github.com/kerphi)) - Fix to set state.error before throw the exception [\#120](https://github.com/shelljs/shelljs/pull/120) ([abdul-martinez](https://github.com/abdul-martinez)) - Add -l and -s support to grep. [\#116](https://github.com/shelljs/shelljs/pull/116) ([idearat](https://github.com/idearat)) From cb9cf276cb0286ad4c54ed8a4d2a5f437b211043 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Fri, 19 Jan 2018 16:33:34 -0800 Subject: [PATCH 38/71] Revert "refactor(exec): remove paramsFile (#807)" (#819) This reverts commit 64d5899abc86dd7b7fa84455c0ce3551786c4b5b. Reason for revert: If stdin is large, then the param object can become an extremely long string, exceeding the maximum OS size limit on commandline parameters. Original change's description: > refactor(exec): remove paramsFile (#807) > > The `paramsFile` is obsolete now that we use `execFileSync()` for our > internal implementation. Instead, we pass parameters to the child > process directly as a single commandline parameter to reduce file I/O. > > Issue #782 Fixes #818 --- src/exec-child.js | 5 ++++- src/exec.js | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/exec-child.js b/src/exec-child.js index 4859e0328..eab86ed37 100644 --- a/src/exec-child.js +++ b/src/exec-child.js @@ -5,7 +5,10 @@ if (require.main !== module) { var childProcess = require('child_process'); var fs = require('fs'); -var params = JSON.parse(process.argv[2]); +var paramFilePath = process.argv[2]; + +var serializedParams = fs.readFileSync(paramFilePath, 'utf8'); +var params = JSON.parse(serializedParams); var cmd = params.command; var execOptions = params.execOptions; diff --git a/src/exec.js b/src/exec.js index ea5793488..03f9826b5 100644 --- a/src/exec.js +++ b/src/exec.js @@ -21,6 +21,7 @@ function execSync(cmd, opts, pipe) { } var tempDir = _tempDir(); + var paramsFile = path.resolve(tempDir + '/' + common.randomFileName()); var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName()); @@ -32,6 +33,7 @@ function execSync(cmd, opts, pipe) { encoding: 'utf8', }, opts); + if (fs.existsSync(paramsFile)) common.unlinkSync(paramsFile); if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile); @@ -45,9 +47,11 @@ function execSync(cmd, opts, pipe) { stderrFile: stderrFile, }; + fs.writeFileSync(paramsFile, JSON.stringify(paramsToSerialize), 'utf8'); + var execArgs = [ path.join(__dirname, 'exec-child.js'), - JSON.stringify(paramsToSerialize), + paramsFile, ]; /* istanbul ignore else */ @@ -84,6 +88,7 @@ function execSync(cmd, opts, pipe) { } // No biggie if we can't erase the files now -- they're in a temp dir anyway + try { common.unlinkSync(paramsFile); } catch (e) {} try { common.unlinkSync(stderrFile); } catch (e) {} try { common.unlinkSync(stdoutFile); } catch (e) {} From 7058d63048e65d33d62b8ba1160f7e852f8f118c Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 20 Jan 2018 14:58:43 -0800 Subject: [PATCH 39/71] 0.8.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 08076f63d..e22598d11 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.8.0", + "version": "0.8.1", "description": "Portable Unix shell commands for Node.js", "keywords": [ "shelljs", From bbcfa5c63eec76e01340e6d2434935701ba22c66 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 20 Jan 2018 15:17:50 -0800 Subject: [PATCH 40/71] docs(changelog): updated by Nate Fischer [ci skip] --- CHANGELOG.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35171d608..89409338a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Change Log +## [v0.8.1](https://github.com/shelljs/shelljs/tree/v0.8.1) (2018-01-20) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.8.0...v0.8.1) + +**Closed issues:** + +- Exec failing with internal error when piping large output [\#818](https://github.com/shelljs/shelljs/issues/818) +- Shelljs exec\(\) not executing variables [\#815](https://github.com/shelljs/shelljs/issues/815) +- support for node-0.10.\* is broken [\#814](https://github.com/shelljs/shelljs/issues/814) +- using sed to replace just the first occurrence of a string [\#813](https://github.com/shelljs/shelljs/issues/813) + +**Merged pull requests:** + +- Revert "refactor\(exec\): remove paramsFile \(\#807\)" [\#819](https://github.com/shelljs/shelljs/pull/819) ([nfischer](https://github.com/nfischer)) + ## [v0.8.0](https://github.com/shelljs/shelljs/tree/v0.8.0) (2018-01-12) [Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.8...v0.8.0) @@ -29,9 +43,7 @@ - shelljs is no longer used in PDF.js [\#737](https://github.com/shelljs/shelljs/issues/737) - ls doesn't follow links to directories [\#733](https://github.com/shelljs/shelljs/issues/733) - Add test for `ls regular-file.txt` [\#732](https://github.com/shelljs/shelljs/issues/732) -- shelljs.exec hangs when password it's asked [\#716](https://github.com/shelljs/shelljs/issues/716) - Clean up common tests [\#714](https://github.com/shelljs/shelljs/issues/714) -- Can't run docker with exec\(\) \(the input device is not a TTY\) [\#680](https://github.com/shelljs/shelljs/issues/680) - Cant get encoding buffer to work on exec [\#675](https://github.com/shelljs/shelljs/issues/675) - Set up Codecov for the project [\#671](https://github.com/shelljs/shelljs/issues/671) - ShellJS: internal error Error: EBUSY: resource busy or locked, lstat 'C:\pagefile.sys' [\#514](https://github.com/shelljs/shelljs/issues/514) @@ -192,7 +204,6 @@ - bug: cp\(\) doesn't always copy everything [\#547](https://github.com/shelljs/shelljs/issues/547) - User-friendly lint command [\#544](https://github.com/shelljs/shelljs/issues/544) - Lint warning [\#542](https://github.com/shelljs/shelljs/issues/542) -- Possible Regression: cp from 0.6.0 to 0.7.x version [\#538](https://github.com/shelljs/shelljs/issues/538) - chore: add nodejs v7 to CI [\#537](https://github.com/shelljs/shelljs/issues/537) - error.code is not always available [\#536](https://github.com/shelljs/shelljs/issues/536) - Add shx as a dependency for testing [\#525](https://github.com/shelljs/shelljs/issues/525) @@ -367,7 +378,6 @@ - Stdout is empty on Git log command [\#439](https://github.com/shelljs/shelljs/issues/439) - Cannot read toString of null when using execSync [\#415](https://github.com/shelljs/shelljs/issues/415) - cp -R dir/ target fails to copy hidden files in dir [\#140](https://github.com/shelljs/shelljs/issues/140) -- Adding callback to basic commands [\#102](https://github.com/shelljs/shelljs/issues/102) - \#mv Won't Work Across Disks [\#1](https://github.com/shelljs/shelljs/issues/1) **Merged pull requests:** @@ -397,8 +407,6 @@ **Closed issues:** - exec\('nohup node some.js &'\) [\#426](https://github.com/shelljs/shelljs/issues/426) -- cp copy to symlinked folder [\#414](https://github.com/shelljs/shelljs/issues/414) -- Invalid version number \(0.0.1alpha1\) [\#399](https://github.com/shelljs/shelljs/issues/399) - shelljs Breaks SemVer for Alpha and Pre-Release Versions [\#390](https://github.com/shelljs/shelljs/issues/390) - Copy not accepting source end with wildcards \* when using -r on v0.6.0 [\#389](https://github.com/shelljs/shelljs/issues/389) - Support globbing in `shjs` [\#388](https://github.com/shelljs/shelljs/issues/388) @@ -417,7 +425,6 @@ - "exec" causes LiveScript interpreter \(lsc\) to hang [\#160](https://github.com/shelljs/shelljs/issues/160) - Don't modify string prototype [\#159](https://github.com/shelljs/shelljs/issues/159) - `exec\(...\).to\(file\)` should work [\#154](https://github.com/shelljs/shelljs/issues/154) -- Would like to see more async variants for cp/rm etc [\#144](https://github.com/shelljs/shelljs/issues/144) - Can't install shelljs locally instead of globally [\#136](https://github.com/shelljs/shelljs/issues/136) - shelljs and node 0.10.28 [\#125](https://github.com/shelljs/shelljs/issues/125) - Use case for global installed shelljs [\#123](https://github.com/shelljs/shelljs/issues/123) @@ -521,7 +528,6 @@ - sed\(\) should accept multiple file arguments [\#231](https://github.com/shelljs/shelljs/issues/231) - shelljs.exec\('aaa && bbb'\) blocks [\#229](https://github.com/shelljs/shelljs/issues/229) - Consider creating a GitHub Organization with more maintainers [\#223](https://github.com/shelljs/shelljs/issues/223) -- Doesn't work inside Electron [\#220](https://github.com/shelljs/shelljs/issues/220) - \[idea\] Add chmodr function. [\#219](https://github.com/shelljs/shelljs/issues/219) - Execute a file [\#211](https://github.com/shelljs/shelljs/issues/211) - Where is standard error going to? [\#209](https://github.com/shelljs/shelljs/issues/209) @@ -533,7 +539,6 @@ - Cannot recursively list all \*.js files [\#162](https://github.com/shelljs/shelljs/issues/162) - exec\(\) breaks if executed in a deleted directory [\#157](https://github.com/shelljs/shelljs/issues/157) - shjs command always exits with zero code [\#133](https://github.com/shelljs/shelljs/issues/133) -- Windows failing tests [\#127](https://github.com/shelljs/shelljs/issues/127) - touch command [\#122](https://github.com/shelljs/shelljs/issues/122) - Symbolic links are broken! [\#100](https://github.com/shelljs/shelljs/issues/100) - interpret `--` as stdin [\#55](https://github.com/shelljs/shelljs/issues/55) From 2271080e4f120b61169ca5659c69c6bf148bbc85 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 25 Jan 2018 00:05:25 -0800 Subject: [PATCH 41/71] chore: update contributing guidelines (#817) This updates some contributing guidelines: * Defer to ISSUE_TEMPLATE.md for filing bugs * Mention eslint and how to automatically fix style mistakes --- CONTRIBUTING.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16257e158..a6b32ba32 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,12 +5,10 @@ We love to receive bug reports (we're always trying to make ShellJS more stable). If you've found a bug, please follow these steps: - - Search for any issues that may have been created already. We often receive - duplicates, and cutting down on this is helpful. If someone else has already - reported it, please ping that issue thread. - - Let us know your version of NodeJS (`node -v`), your version of ShellJS (from - `package.json`), your OS, and any other useful information. - - Give an example ShellJS command to reproduce the error. + - Please try to cut down on duplicates. Please search for issues which have + already been reported (remember to search closed issues). + - Please see [`ISSUE_TEMPLATE.md`](.github/ISSUE_TEMPLATE.md) for more + information. ## Pull requests @@ -20,7 +18,9 @@ PRs are welcome! However, we ask that you follow a few guidelines: - Make sure your code passes `npm test`. Please check the CI (both Appveyor and Travis). If you can't figure out why something doesn't work, feel free to ask for help. - - Make changes to the documentation *within the source files*, not in the - README. Then update the README by running `node scripts/generate-docs.js`. + - Make sure you conform to our style guidelines. You can run `npm run lint` to + check style, and `npm run lint -- --fix` to automatically fix some issues. + - Make documentation changes *within the source files*, not in the README. + Update the README with `npm run gendocs`. - Please keep your PR up to date (either via rebase or by pressing the "update branch" button on Github). From 62ce4bacab6ab980332201ce79e549ac2e4ae03a Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 25 Jan 2018 13:51:50 -0800 Subject: [PATCH 42/71] chore(lint): don't allow excess trailing newlines (#816) * chore(lint): don't allow excess trailing newlines This enforces that files should not end with blank lines (i.e. more than one trailing newline). The `eol-last` rule (inherited from airbnb's config) already enforces that files end in at least one trailing newline, so adding this rule enforces that it ends in exactly 1. See https://eslint.org/docs/rules/no-multiple-empty-lines and https://eslint.org/docs/rules/eol-last for more information. Inspired by #809. * add maxBOF --- .eslintrc.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.json b/.eslintrc.json index 7037c1760..f96d7f578 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -23,6 +23,7 @@ "consistent-return": "off", "no-mixed-operators": "off", "no-prototype-builtins": "off", + "no-multiple-empty-lines": ["error", { "max": 2, "maxBOF": 0, "maxEOF": 0 } ], "new-cap": ["error", { "capIsNewExceptions": [ "ShellString" From 9077f4171e30520565a1a964a2270023f375cf1d Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Mon, 29 Jan 2018 12:28:02 -0800 Subject: [PATCH 43/71] Remove separate "internal error" from exec (#802) * Remove separate "internal error" from exec * Fix unknown command error regex * Add message about command not found regex * Silence errors while reading files in exec The stdout and stderr files may never be opened or written to in certain circumstances. In particular, if the timeout is short enough, the child node process does not have enough time to start, and the child script does not execute, so the files are not written to. So, catch errors form trying to read the files, and ignore them. * Do not silence errors due to short timeouts * Simplify test regex for missing command * Default error code to 1 if not set --- src/exec.js | 25 ++++++++++++------------- test/exec.js | 4 ++-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/exec.js b/src/exec.js index 03f9826b5..b791cf896 100644 --- a/src/exec.js +++ b/src/exec.js @@ -6,6 +6,7 @@ var fs = require('fs'); var child = require('child_process'); var DEFAULT_MAXBUFFER_SIZE = 20 * 1024 * 1024; +var DEFAULT_ERROR_CODE = 1; common.register('exec', _exec, { unix: false, @@ -72,13 +73,15 @@ function execSync(cmd, opts, pipe) { child.execFileSync(common.config.execPath, execArgs, opts); } catch (e) { // Commands with non-zero exit code raise an exception. - code = e.status; + code = e.status || DEFAULT_ERROR_CODE; } // fs.readFileSync uses buffer encoding by default, so call - // it without the encoding option if the encoding is 'buffer' - var stdout; - var stderr; + // it without the encoding option if the encoding is 'buffer'. + // Also, if the exec timeout is too short for node to start up, + // the files will not be created, so these calls will throw. + var stdout = ''; + var stderr = ''; if (opts.encoding === 'buffer') { stdout = fs.readFileSync(stdoutFile); stderr = fs.readFileSync(stderrFile); @@ -93,7 +96,7 @@ function execSync(cmd, opts, pipe) { try { common.unlinkSync(stdoutFile); } catch (e) {} if (code !== 0) { - common.error('', code, { continue: true }); + common.error(stderr, code, { continue: true }); } var obj = common.ShellString(stdout, stderr, code); return obj; @@ -196,14 +199,10 @@ function _exec(command, options, callback) { async: false, }, options); - try { - if (options.async) { - return execAsync(command, options, pipe, callback); - } else { - return execSync(command, options, pipe); - } - } catch (e) { - common.error('internal error'); + if (options.async) { + return execAsync(command, options, pipe, callback); + } else { + return execSync(command, options, pipe); } } module.exports = _exec; diff --git a/test/exec.js b/test/exec.js index cdd87a653..2cd2a67fd 100644 --- a/test/exec.js +++ b/test/exec.js @@ -35,7 +35,7 @@ test('config.fatal and unknown command', t => { shell.config.fatal = true; t.throws(() => { shell.exec('asdfasdf'); // could not find command - }, /exec: internal error/); + }, /asdfasdf/); // name of command should be in error message shell.config.fatal = oldFatal; }); @@ -127,7 +127,7 @@ test('set timeout option', t => { const result = shell.exec(`${JSON.stringify(shell.config.execPath)} test/resources/exec/slow.js 100`); // default timeout is ok t.falsy(shell.error()); t.is(result.code, 0); - shell.exec(`${JSON.stringify(shell.config.execPath)} test/resources/exec/slow.js 100`, { timeout: 10 }); // times out + shell.exec(`${JSON.stringify(shell.config.execPath)} test/resources/exec/slow.js 2000`, { timeout: 1000 }); // times out t.truthy(shell.error()); }); From 9035b27403c7e3c3dc801939d20dec8fe6143c06 Mon Sep 17 00:00:00 2001 From: Zearin Date: Tue, 20 Feb 2018 01:21:17 -0500 Subject: [PATCH 44/71] docs: fix typos and adjust markdown formatting (#825) Miscellaneous docs/markdown changes. No change to logic. --- README.md | 133 +++++++++++++++++++++++++++++--------------------- shell.js | 14 +++--- src/cat.js | 1 + src/cd.js | 1 + src/chmod.js | 8 +-- src/common.js | 2 +- src/cp.js | 3 +- src/dirs.js | 14 +++--- src/echo.js | 3 +- src/error.js | 3 +- src/exec.js | 15 +++--- src/find.js | 7 +-- src/grep.js | 3 +- src/head.js | 1 + src/ln.js | 3 +- src/ls.js | 6 ++- src/mkdir.js | 5 +- src/mv.js | 3 +- src/pwd.js | 1 + src/rm.js | 1 + src/sed.js | 7 +-- src/set.js | 3 +- src/sort.js | 7 +-- src/tail.js | 5 +- src/test.js | 3 +- src/to.js | 2 +- src/toEnd.js | 2 +- src/touch.js | 11 +++-- src/uniq.js | 3 +- src/which.js | 8 +-- 30 files changed, 162 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index d5f577951..cf916b94c 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ shell.echo('hello world'); All commands run synchronously, unless otherwise stated. All commands accept standard bash globbing characters (`*`, `?`, etc.), -compatible with the [node glob module](https://github.com/isaacs/node-glob). +compatible with the [node `glob` module](https://github.com/isaacs/node-glob). For less-commonly used commands and features, please check out our [wiki page](https://github.com/shelljs/shelljs/wiki). @@ -139,6 +139,7 @@ page](https://github.com/shelljs/shelljs/wiki). ### cat([options,] file [, file ...]) ### cat([options,] file_array) + Available options: + `-n`: number all output lines @@ -157,6 +158,7 @@ introduced between each file). ### cd([dir]) + Changes to directory `dir` for the duration of the script. Changes to home directory if no argument is supplied. @@ -167,7 +169,7 @@ directory if no argument is supplied. Available options: + `-v`: output a diagnostic for every file processed -+ `-c`: like verbose but report only when a change is made ++ `-c`: like verbose, but report only when a change is made + `-R`: change files and directories recursively Examples: @@ -184,18 +186,19 @@ absolute permissions in octal form or expressing the changes in symbols. This command tries to mimic the POSIX behavior as much as possible. Notable exceptions: -+ In symbolic modes, 'a-r' and '-r' are identical. No consideration is - given to the umask. -+ There is no "quiet" option since default behavior is to run silent. ++ In symbolic modes, `a-r` and `-r` are identical. No consideration is + given to the `umask`. ++ There is no "quiet" option, since default behavior is to run silent. ### cp([options,] source [, source ...], dest) ### cp([options,] source_array, dest) + Available options: + `-f`: force (default behavior) + `-n`: no-clobber -+ `-u`: only copy if source is newer than dest ++ `-u`: only copy if `source` is newer than `dest` + `-r`, `-R`: recursive + `-L`: follow symlinks + `-P`: don't follow symlinks @@ -221,7 +224,7 @@ Available options: Arguments: -+ `dir`: Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir`. ++ `dir`: Sets the current working directory to the top of the stack, then executes the equivalent of `cd dir`. + `+N`: Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. + `-N`: Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. @@ -233,13 +236,14 @@ pushd('/etc'); // Returns /etc /usr pushd('+1'); // Returns /usr /etc ``` -Save the current directory on the top of the directory stack and then cd to `dir`. With no arguments, pushd exchanges the top two directories. Returns an array of paths in the stack. +Save the current directory on the top of the directory stack and then `cd` to `dir`. With no arguments, `pushd` exchanges the top two directories. Returns an array of paths in the stack. + ### popd([options,] ['-N' | '+N']) Available options: -+ `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. ++ `-n`: Suppress the normal directory change when removing directories from the stack, so that only the stack is manipulated. + `-q`: Supresses output to the console. Arguments: @@ -257,7 +261,8 @@ popd(); // '/usr' echo(process.cwd()); // '/usr' ``` -When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs; i.e., popd is equivalent to popd +0. Returns an array of paths in the stack. +When no arguments are given, `popd` removes the top directory from the stack and performs a `cd` to the new top directory. The elements are numbered from 0, starting at the first directory listed with dirs (i.e., `popd` is equivalent to `popd +0`). Returns an array of paths in the stack. + ### dirs([options | '+N' | '-N']) @@ -271,12 +276,13 @@ Arguments: + `+N`: Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero. + `-N`: Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero. -Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if +N or -N was specified. +Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if `+N` or `-N` was specified. -See also: pushd, popd +See also: `pushd`, `popd` ### echo([options,] string [, string ...]) + Available options: + `-e`: interpret backslash escapes (default) @@ -290,20 +296,21 @@ var str = echo('hello world'); echo('-n', 'no newline at end'); ``` -Prints string to stdout, and returns string with additional utility methods +Prints `string` to stdout, and returns string with additional utility methods like `.to()`. ### exec(command [, options] [, callback]) + Available options: + `async`: Asynchronous execution. If a callback is provided, it will be set to `true`, regardless of the passed value (default: `false`). + `silent`: Do not echo program output to console (default: `false`). -+ `encoding`: Character encoding to use. Affects the returned stdout and stderr values, and ++ `encoding`: Character encoding to use. Affects the values returned to stdout and stderr, and what is written to stdout and stderr when not in silent mode (default: `'utf8'`). + and any option available to Node.js's - [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) + [`child_process.exec()`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) Examples: @@ -323,21 +330,18 @@ exec('some_long_running_process', function(code, stdout, stderr) { ``` Executes the given `command` _synchronously_, unless otherwise specified. When in synchronous -mode, this returns a ShellString (compatible with ShellJS v0.6.x, which returns an object +mode, this returns a `ShellString` (compatible with ShellJS v0.6.x, which returns an object of the form `{ code:..., stdout:... , stderr:... }`). Otherwise, this returns the child process -object, and the `callback` gets the arguments `(code, stdout, stderr)`. +object, and the `callback` receives the arguments `(code, stdout, stderr)`. Not seeing the behavior you want? `exec()` runs everything through `sh` by default (or `cmd.exe` on Windows), which differs from `bash`. If you need bash-specific behavior, try out the `{shell: 'path/to/bash'}` option. -**Note:** For long-lived processes, it's best to run `exec()` asynchronously as -the current synchronous implementation uses a lot of CPU. This should be getting -fixed soon. - ### find(path [, path ...]) ### find(path_array) + Examples: ```javascript @@ -349,14 +353,15 @@ find('.').filter(function(file) { return file.match(/\.js$/); }); Returns array of all files (however deep) in the given paths. The main difference from `ls('-R', path)` is that the resulting file names -include the base directories, e.g. `lib/resources/file1` instead of just `file1`. +include the base directories (e.g., `lib/resources/file1` instead of just `file1`). ### grep([options,] regex_filter, file [, file ...]) ### grep([options,] regex_filter, file_array) + Available options: -+ `-v`: Inverse the sense of the regex and print the lines not matching the criteria. ++ `-v`: Invert `regex_filter` (only print non-matching lines). + `-l`: Print only filenames of matching files Examples: @@ -372,6 +377,7 @@ file that match the given `regex_filter`. ### head([{'-n': \},] file [, file ...]) ### head([{'-n': \},] file_array) + Available options: + `-n `: Show the first `` lines of the files @@ -388,6 +394,7 @@ Read the start of a file. ### ln([options,] source, dest) + Available options: + `-s`: symlink @@ -400,11 +407,12 @@ ln('file', 'newlink'); ln('-sf', 'file', 'existing'); ``` -Links source to dest. Use -f to force the link, should dest already exist. +Links `source` to `dest`. Use `-f` to force the link, should `dest` already exist. ### ls([options,] [path, ...]) ### ls([options,] path_array) + Available options: + `-R`: recursive @@ -413,7 +421,7 @@ Available options: + `-d`: list directories themselves, not their contents + `-l`: list objects representing each file, each with fields containing `ls -l` output fields. See - [fs.Stats](https://nodejs.org/api/fs.html#fs_class_fs_stats) + [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) for more info Examples: @@ -425,14 +433,16 @@ ls('-R', ['/users/me', '/tmp']); // same as above ls('-l', 'file.txt'); // { name: 'file.txt', mode: 33188, nlink: 1, ...} ``` -Returns array of files in the given path, or in current directory if no path provided. +Returns array of files in the given `path`, or files in +the current directory if no `path` is provided. ### mkdir([options,] dir [, dir ...]) ### mkdir([options,] dir_array) + Available options: -+ `-p`: full path (will create intermediate dirs if necessary) ++ `-p`: full path (and create intermediate directories, if necessary) Examples: @@ -446,6 +456,7 @@ Creates directories. ### mv([options ,] source [, source ...], dest') ### mv([options ,] source_array, dest') + Available options: + `-f`: force (default behavior) @@ -459,15 +470,17 @@ mv('file1', 'file2', 'dir/'); mv(['file1', 'file2'], 'dir/'); // same as above ``` -Moves files. +Moves `source` file(s) to `dest`. ### pwd() + Returns the current directory. ### rm([options,] file [, file ...]) ### rm([options,] file_array) + Available options: + `-f`: force @@ -486,9 +499,10 @@ Removes files. ### sed([options,] search_regex, replacement, file [, file ...]) ### sed([options,] search_regex, replacement, file_array) + Available options: -+ `-i`: Replace contents of 'file' in-place. _Note that no backups will be created!_ ++ `-i`: Replace contents of `file` in-place. _Note that no backups will be created!_ Examples: @@ -497,8 +511,8 @@ sed('-i', 'PROGRAM_VERSION', 'v0.1.3', 'source.js'); sed(/.*DELETE_THIS_LINE.*\n/, '', 'source.js'); ``` -Reads an input string from `files` and performs a JavaScript `replace()` on the input -using the given search regex and replacement string or function. Returns the new string after replacement. +Reads an input string from `file`s, and performs a JavaScript `replace()` on the input +using the given `search_regex` and `replacement` string or function. Returns the new string after replacement. Note: @@ -511,6 +525,7 @@ sed(/(\w+)\s(\w+)/, '$2, $1', 'file.txt'); ### set(options) + Available options: + `+/-e`: exit upon error (`config.fatal`) @@ -524,14 +539,15 @@ set('-e'); // exit upon first error set('+e'); // this undoes a "set('-e')" ``` -Sets global configuration variables +Sets global configuration variables. ### sort([options,] file [, file ...]) ### sort([options,] file_array) + Available options: -+ `-r`: Reverse the result of comparisons ++ `-r`: Reverse the results + `-n`: Compare according to numerical value Examples: @@ -541,15 +557,16 @@ sort('foo.txt', 'bar.txt'); sort('-r', 'foo.txt'); ``` -Return the contents of the files, sorted line-by-line. Sorting multiple -files mixes their content, just like unix sort does. +Return the contents of the `file`s, sorted line-by-line. Sorting multiple +files mixes their content (just as unix `sort` does). ### tail([{'-n': \},] file [, file ...]) ### tail([{'-n': \},] file_array) + Available options: -+ `-n `: Show the last `` lines of the files ++ `-n `: Show the last `` lines of `file`s Examples: @@ -559,7 +576,7 @@ var str = tail('file1', 'file2'); var str = tail(['file1', 'file2']); // same as above ``` -Read the end of a file. +Read the end of a `file`. ### tempdir() @@ -575,6 +592,7 @@ Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.ht ### test(expression) + Available expression primaries: + `'-b', 'path'`: true if path is a block device @@ -593,7 +611,7 @@ if (test('-d', path)) { /* do something with dir */ }; if (!test('-f', path)) continue; // skip if it's a regular file ``` -Evaluates expression using the available primaries and returns corresponding value. +Evaluates `expression` using the available primaries and returns corresponding value. ### ShellString.prototype.to(file) @@ -605,7 +623,7 @@ cat('input.txt').to('output.txt'); ``` Analogous to the redirection operator `>` in Unix, but works with -ShellStrings (such as those returned by `cat`, `grep`, etc). _Like Unix +`ShellStrings` (such as those returned by `cat`, `grep`, etc.). _Like Unix redirections, `to()` will overwrite any existing file!_ @@ -618,18 +636,19 @@ cat('input.txt').toEnd('output.txt'); ``` Analogous to the redirect-and-append operator `>>` in Unix, but works with -ShellStrings (such as those returned by `cat`, `grep`, etc). +`ShellStrings` (such as those returned by `cat`, `grep`, etc.). ### touch([options,] file [, file ...]) ### touch([options,] file_array) + Available options: + `-a`: Change only the access time + `-c`: Do not create any files + `-m`: Change only the modification time -+ `-d DATE`: Parse DATE and use it instead of current time -+ `-r FILE`: Use FILE's times instead of current time ++ `-d DATE`: Parse `DATE` and use it instead of current time ++ `-r FILE`: Use `FILE`'s times instead of current time Examples: @@ -639,12 +658,13 @@ touch('-c', '/path/to/some/dir/source.js'); touch({ '-r': FILE }, '/path/to/some/dir/source.js'); ``` -Update the access and modification times of each FILE to the current time. -A FILE argument that does not exist is created empty, unless -c is supplied. -This is a partial implementation of *[touch(1)](http://linux.die.net/man/1/touch)*. +Update the access and modification times of each `FILE` to the current time. +A `FILE` argument that does not exist is created empty, unless `-c` is supplied. +This is a partial implementation of [`touch(1)`](http://linux.die.net/man/1/touch). ### uniq([options,] [input, [output]]) + Available options: + `-i`: Ignore case while comparing @@ -659,7 +679,7 @@ uniq('-i', 'foo.txt'); uniq('-cd', 'foo.txt', 'bar.txt'); ``` -Filter adjacent matching lines from input +Filter adjacent matching lines from `input`. ### which(command) @@ -670,17 +690,19 @@ Examples: var nodeExec = which('node'); ``` -Searches for `command` in the system's PATH. On Windows, this uses the +Searches for `command` in the system's `PATH`. On Windows, this uses the `PATHEXT` variable to append the extension if it's not already executable. -Returns string containing the absolute path to the command. +Returns string containing the absolute path to `command`. ### exit(code) -Exits the current process with the given exit code. + +Exits the current process with the given exit `code`. ### error() + Tests if error occurred in the last command. Returns a truthy value if an -error returned and a falsy value otherwise. +error returned, or a falsy value otherwise. **Note**: do not rely on the return value to be an error message. If you need the last error message, use @@ -696,12 +718,13 @@ var foo = ShellString('hello world'); ``` Turns a regular string into a string-like object similar to what each -command returns. This has special methods, like `.to()` and `.toEnd()` +command returns. This has special methods, like `.to()` and `.toEnd()`. ### env['VAR_NAME'] + Object containing environment variables (both getter and setter). Shortcut -to process.env. +to `process.env`. ### Pipes @@ -746,9 +769,9 @@ cp('this_file_does_not_exist', '/dev/null'); // throws Error here /* more commands... */ ``` -If `true` the script will throw a Javascript error when any shell.js +If `true`, the script will throw a Javascript error when any shell.js command encounters an error. Default is `false`. This is analogous to -Bash's `set -e` +Bash's `set -e`. ### config.verbose @@ -792,7 +815,7 @@ shell.config.reset(); // reset to original state /* ... */ ``` -Reset shell.config to the defaults: +Reset `shell.config` to the defaults: ```javascript { diff --git a/shell.js b/shell.js index 2541a2036..f9c6f36df 100644 --- a/shell.js +++ b/shell.js @@ -11,7 +11,7 @@ var common = require('./src/common'); //@ //@ All commands run synchronously, unless otherwise stated. //@ All commands accept standard bash globbing characters (`*`, `?`, etc.), -//@ compatible with the [node glob module](https://github.com/isaacs/node-glob). +//@ compatible with the [node `glob` module](https://github.com/isaacs/node-glob). //@ //@ For less-commonly used commands and features, please check out our [wiki //@ page](https://github.com/shelljs/shelljs/wiki). @@ -27,7 +27,8 @@ require('./commands').forEach(function (command) { //@ //@ ### exit(code) -//@ Exits the current process with the given exit code. +//@ +//@ Exits the current process with the given exit `code`. exports.exit = process.exit; //@include ./src/error @@ -38,8 +39,9 @@ exports.ShellString = common.ShellString; //@ //@ ### env['VAR_NAME'] +//@ //@ Object containing environment variables (both getter and setter). Shortcut -//@ to process.env. +//@ to `process.env`. exports.env = process.env; //@ @@ -91,9 +93,9 @@ exports.config = common.config; //@ /* more commands... */ //@ ``` //@ -//@ If `true` the script will throw a Javascript error when any shell.js +//@ If `true`, the script will throw a Javascript error when any shell.js //@ command encounters an error. Default is `false`. This is analogous to -//@ Bash's `set -e` +//@ Bash's `set -e`. //@ //@ ### config.verbose @@ -140,7 +142,7 @@ exports.config = common.config; //@ /* ... */ //@ ``` //@ -//@ Reset shell.config to the defaults: +//@ Reset `shell.config` to the defaults: //@ //@ ```javascript //@ { diff --git a/src/cat.js b/src/cat.js index cdad1b0f6..c5c44347c 100644 --- a/src/cat.js +++ b/src/cat.js @@ -11,6 +11,7 @@ common.register('cat', _cat, { //@ //@ ### cat([options,] file [, file ...]) //@ ### cat([options,] file_array) +//@ //@ Available options: //@ //@ + `-n`: number all output lines diff --git a/src/cd.js b/src/cd.js index 87ce9b9a7..27bc21075 100644 --- a/src/cd.js +++ b/src/cd.js @@ -5,6 +5,7 @@ common.register('cd', _cd, {}); //@ //@ ### cd([dir]) +//@ //@ Changes to directory `dir` for the duration of the script. Changes to home //@ directory if no argument is supplied. function _cd(options, dir) { diff --git a/src/chmod.js b/src/chmod.js index 758c6e515..bcc3a0370 100644 --- a/src/chmod.js +++ b/src/chmod.js @@ -39,7 +39,7 @@ common.register('chmod', _chmod, { //@ Available options: //@ //@ + `-v`: output a diagnostic for every file processed//@ -//@ + `-c`: like verbose but report only when a change is made//@ +//@ + `-c`: like verbose, but report only when a change is made//@ //@ + `-R`: change files and directories recursively//@ //@ //@ Examples: @@ -56,9 +56,9 @@ common.register('chmod', _chmod, { //@ This command tries to mimic the POSIX behavior as much as possible. //@ Notable exceptions: //@ -//@ + In symbolic modes, 'a-r' and '-r' are identical. No consideration is -//@ given to the umask. -//@ + There is no "quiet" option since default behavior is to run silent. +//@ + In symbolic modes, `a-r` and `-r` are identical. No consideration is +//@ given to the `umask`. +//@ + There is no "quiet" option, since default behavior is to run silent. function _chmod(options, mode, filePattern) { if (!filePattern) { if (options.length > 0 && options.charAt(0) === '-') { diff --git a/src/common.js b/src/common.js index facd72fe1..f873782bc 100644 --- a/src/common.js +++ b/src/common.js @@ -129,7 +129,7 @@ exports.error = error; //@ ``` //@ //@ Turns a regular string into a string-like object similar to what each -//@ command returns. This has special methods, like `.to()` and `.toEnd()` +//@ command returns. This has special methods, like `.to()` and `.toEnd()`. function ShellString(stdout, stderr, code) { var that; if (stdout instanceof Array) { diff --git a/src/cp.js b/src/cp.js index d46a54ab5..4214b0bdf 100644 --- a/src/cp.js +++ b/src/cp.js @@ -186,11 +186,12 @@ function cpcheckcycle(sourceDir, srcFile) { //@ //@ ### cp([options,] source [, source ...], dest) //@ ### cp([options,] source_array, dest) +//@ //@ Available options: //@ //@ + `-f`: force (default behavior) //@ + `-n`: no-clobber -//@ + `-u`: only copy if source is newer than dest +//@ + `-u`: only copy if `source` is newer than `dest` //@ + `-r`, `-R`: recursive //@ + `-L`: follow symlinks //@ + `-P`: don't follow symlinks diff --git a/src/dirs.js b/src/dirs.js index 3e27ac95e..26547a5b3 100644 --- a/src/dirs.js +++ b/src/dirs.js @@ -44,7 +44,7 @@ function _actualDirStack() { //@ //@ Arguments: //@ -//@ + `dir`: Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir`. +//@ + `dir`: Sets the current working directory to the top of the stack, then executes the equivalent of `cd dir`. //@ + `+N`: Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. //@ + `-N`: Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. //@ @@ -56,7 +56,7 @@ function _actualDirStack() { //@ pushd('+1'); // Returns /usr /etc //@ ``` //@ -//@ Save the current directory on the top of the directory stack and then cd to `dir`. With no arguments, pushd exchanges the top two directories. Returns an array of paths in the stack. +//@ Save the current directory on the top of the directory stack and then `cd` to `dir`. With no arguments, `pushd` exchanges the top two directories. Returns an array of paths in the stack. function _pushd(options, dir) { if (_isStackIndex(options)) { dir = options; @@ -101,12 +101,13 @@ function _pushd(options, dir) { } exports.pushd = _pushd; +//@ //@ //@ ### popd([options,] ['-N' | '+N']) //@ //@ Available options: //@ -//@ + `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. +//@ + `-n`: Suppress the normal directory change when removing directories from the stack, so that only the stack is manipulated. //@ + `-q`: Supresses output to the console. //@ //@ Arguments: @@ -124,7 +125,7 @@ exports.pushd = _pushd; //@ echo(process.cwd()); // '/usr' //@ ``` //@ -//@ When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs; i.e., popd is equivalent to popd +0. Returns an array of paths in the stack. +//@ When no arguments are given, `popd` removes the top directory from the stack and performs a `cd` to the new top directory. The elements are numbered from 0, starting at the first directory listed with dirs (i.e., `popd` is equivalent to `popd +0`). Returns an array of paths in the stack. function _popd(options, index) { if (_isStackIndex(options)) { index = options; @@ -154,6 +155,7 @@ function _popd(options, index) { } exports.popd = _popd; +//@ //@ //@ ### dirs([options | '+N' | '-N']) //@ @@ -167,9 +169,9 @@ exports.popd = _popd; //@ + `+N`: Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero. //@ + `-N`: Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero. //@ -//@ Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if +N or -N was specified. +//@ Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if `+N` or `-N` was specified. //@ -//@ See also: pushd, popd +//@ See also: `pushd`, `popd` function _dirs(options, index) { if (_isStackIndex(options)) { index = options; diff --git a/src/echo.js b/src/echo.js index 7229ce7f2..1b089d59c 100644 --- a/src/echo.js +++ b/src/echo.js @@ -8,6 +8,7 @@ common.register('echo', _echo, { //@ //@ ### echo([options,] string [, string ...]) +//@ //@ Available options: //@ //@ + `-e`: interpret backslash escapes (default) @@ -21,7 +22,7 @@ common.register('echo', _echo, { //@ echo('-n', 'no newline at end'); //@ ``` //@ -//@ Prints string to stdout, and returns string with additional utility methods +//@ Prints `string` to stdout, and returns string with additional utility methods //@ like `.to()`. function _echo(opts) { // allow strings starting with '-', see issue #20 diff --git a/src/error.js b/src/error.js index 507c86ddd..b0ed59e12 100644 --- a/src/error.js +++ b/src/error.js @@ -2,8 +2,9 @@ var common = require('./common'); //@ //@ ### error() +//@ //@ Tests if error occurred in the last command. Returns a truthy value if an -//@ error returned and a falsy value otherwise. +//@ error returned, or a falsy value otherwise. //@ //@ **Note**: do not rely on the //@ return value to be an error message. If you need the last error message, use diff --git a/src/exec.js b/src/exec.js index b791cf896..66ef3d736 100644 --- a/src/exec.js +++ b/src/exec.js @@ -14,7 +14,7 @@ common.register('exec', _exec, { wrapOutput: false, }); -// We use this function to run exec synchronously while also providing realtime +// We use this function to run `exec` synchronously while also providing realtime // output. function execSync(cmd, opts, pipe) { if (!common.config.execPath) { @@ -138,15 +138,16 @@ function execAsync(cmd, opts, pipe, callback) { //@ //@ ### exec(command [, options] [, callback]) +//@ //@ Available options: //@ //@ + `async`: Asynchronous execution. If a callback is provided, it will be set to //@ `true`, regardless of the passed value (default: `false`). //@ + `silent`: Do not echo program output to console (default: `false`). -//@ + `encoding`: Character encoding to use. Affects the returned stdout and stderr values, and +//@ + `encoding`: Character encoding to use. Affects the values returned to stdout and stderr, and //@ what is written to stdout and stderr when not in silent mode (default: `'utf8'`). //@ + and any option available to Node.js's -//@ [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) +//@ [`child_process.exec()`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) //@ //@ Examples: //@ @@ -166,17 +167,13 @@ function execAsync(cmd, opts, pipe, callback) { //@ ``` //@ //@ Executes the given `command` _synchronously_, unless otherwise specified. When in synchronous -//@ mode, this returns a ShellString (compatible with ShellJS v0.6.x, which returns an object +//@ mode, this returns a `ShellString` (compatible with ShellJS v0.6.x, which returns an object //@ of the form `{ code:..., stdout:... , stderr:... }`). Otherwise, this returns the child process -//@ object, and the `callback` gets the arguments `(code, stdout, stderr)`. +//@ object, and the `callback` receives the arguments `(code, stdout, stderr)`. //@ //@ Not seeing the behavior you want? `exec()` runs everything through `sh` //@ by default (or `cmd.exe` on Windows), which differs from `bash`. If you //@ need bash-specific behavior, try out the `{shell: 'path/to/bash'}` option. -//@ -//@ **Note:** For long-lived processes, it's best to run `exec()` asynchronously as -//@ the current synchronous implementation uses a lot of CPU. This should be getting -//@ fixed soon. function _exec(command, options, callback) { options = options || {}; if (!command) common.error('must specify command'); diff --git a/src/find.js b/src/find.js index b28d0378e..0de695ade 100644 --- a/src/find.js +++ b/src/find.js @@ -7,6 +7,7 @@ common.register('find', _find, {}); //@ //@ ### find(path [, path ...]) //@ ### find(path_array) +//@ //@ Examples: //@ //@ ```javascript @@ -18,7 +19,7 @@ common.register('find', _find, {}); //@ Returns array of all files (however deep) in the given paths. //@ //@ The main difference from `ls('-R', path)` is that the resulting file names -//@ include the base directories, e.g. `lib/resources/file1` instead of just `file1`. +//@ include the base directories (e.g., `lib/resources/file1` instead of just `file1`). function _find(options, paths) { if (!paths) { common.error('no path specified'); @@ -35,8 +36,8 @@ function _find(options, paths) { list.push(file); } - // why not simply do ls('-R', paths)? because the output wouldn't give the base dirs - // to get the base dir in the output, we need instead ls('-R', 'dir/*') for every directory + // why not simply do `ls('-R', paths)`? because the output wouldn't give the base dirs + // to get the base dir in the output, we need instead `ls('-R', 'dir/*')` for every directory paths.forEach(function (file) { var stat; diff --git a/src/grep.js b/src/grep.js index 8cf53b157..3880fa191 100644 --- a/src/grep.js +++ b/src/grep.js @@ -13,9 +13,10 @@ common.register('grep', _grep, { //@ //@ ### grep([options,] regex_filter, file [, file ...]) //@ ### grep([options,] regex_filter, file_array) +//@ //@ Available options: //@ -//@ + `-v`: Inverse the sense of the regex and print the lines not matching the criteria. +//@ + `-v`: Invert `regex_filter` (only print non-matching lines). //@ + `-l`: Print only filenames of matching files //@ //@ Examples: diff --git a/src/head.js b/src/head.js index c08ae9ba3..7169fd393 100644 --- a/src/head.js +++ b/src/head.js @@ -33,6 +33,7 @@ function readSomeLines(file, numLines) { //@ //@ ### head([{'-n': \},] file [, file ...]) //@ ### head([{'-n': \},] file_array) +//@ //@ Available options: //@ //@ + `-n `: Show the first `` lines of the files diff --git a/src/ln.js b/src/ln.js index 71f2b3916..2cf87cd89 100644 --- a/src/ln.js +++ b/src/ln.js @@ -11,6 +11,7 @@ common.register('ln', _ln, { //@ //@ ### ln([options,] source, dest) +//@ //@ Available options: //@ //@ + `-s`: symlink @@ -23,7 +24,7 @@ common.register('ln', _ln, { //@ ln('-sf', 'file', 'existing'); //@ ``` //@ -//@ Links source to dest. Use -f to force the link, should dest already exist. +//@ Links `source` to `dest`. Use `-f` to force the link, should `dest` already exist. function _ln(options, source, dest) { if (!source || !dest) { common.error('Missing and/or '); diff --git a/src/ls.js b/src/ls.js index 2f3ac6973..eea99c5ca 100644 --- a/src/ls.js +++ b/src/ls.js @@ -19,6 +19,7 @@ common.register('ls', _ls, { //@ //@ ### ls([options,] [path, ...]) //@ ### ls([options,] path_array) +//@ //@ Available options: //@ //@ + `-R`: recursive @@ -27,7 +28,7 @@ common.register('ls', _ls, { //@ + `-d`: list directories themselves, not their contents //@ + `-l`: list objects representing each file, each with fields containing `ls //@ -l` output fields. See -//@ [fs.Stats](https://nodejs.org/api/fs.html#fs_class_fs_stats) +//@ [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) //@ for more info //@ //@ Examples: @@ -39,7 +40,8 @@ common.register('ls', _ls, { //@ ls('-l', 'file.txt'); // { name: 'file.txt', mode: 33188, nlink: 1, ...} //@ ``` //@ -//@ Returns array of files in the given path, or in current directory if no path provided. +//@ Returns array of files in the given `path`, or files in +//@ the current directory if no `path` is provided. function _ls(options, paths) { if (options.all_deprecated) { // We won't support the -a option as it's hard to image why it's useful diff --git a/src/mkdir.js b/src/mkdir.js index 723c137d2..6168d592b 100644 --- a/src/mkdir.js +++ b/src/mkdir.js @@ -8,7 +8,7 @@ common.register('mkdir', _mkdir, { }, }); -// Recursively creates 'dir' +// Recursively creates `dir` function mkdirSyncRecursive(dir) { var baseDir = path.dirname(dir); @@ -35,9 +35,10 @@ function mkdirSyncRecursive(dir) { //@ //@ ### mkdir([options,] dir [, dir ...]) //@ ### mkdir([options,] dir_array) +//@ //@ Available options: //@ -//@ + `-p`: full path (will create intermediate dirs if necessary) +//@ + `-p`: full path (and create intermediate directories, if necessary) //@ //@ Examples: //@ diff --git a/src/mv.js b/src/mv.js index 525be06b8..ac28a24eb 100644 --- a/src/mv.js +++ b/src/mv.js @@ -22,6 +22,7 @@ function checkRecentCreated(sources, index) { //@ //@ ### mv([options ,] source [, source ...], dest') //@ ### mv([options ,] source_array, dest') +//@ //@ Available options: //@ //@ + `-f`: force (default behavior) @@ -35,7 +36,7 @@ function checkRecentCreated(sources, index) { //@ mv(['file1', 'file2'], 'dir/'); // same as above //@ ``` //@ -//@ Moves files. +//@ Moves `source` file(s) to `dest`. function _mv(options, sources, dest) { // Get sources, dest if (arguments.length < 3) { diff --git a/src/pwd.js b/src/pwd.js index 38618518b..8fcf8fcec 100644 --- a/src/pwd.js +++ b/src/pwd.js @@ -7,6 +7,7 @@ common.register('pwd', _pwd, { //@ //@ ### pwd() +//@ //@ Returns the current directory. function _pwd() { var pwd = path.resolve(process.cwd()); diff --git a/src/rm.js b/src/rm.js index 75dcd7fa4..90409ac68 100644 --- a/src/rm.js +++ b/src/rm.js @@ -149,6 +149,7 @@ function handleFIFO(file) { //@ //@ ### rm([options,] file [, file ...]) //@ ### rm([options,] file_array) +//@ //@ Available options: //@ //@ + `-f`: force diff --git a/src/sed.js b/src/sed.js index 7d396e7e9..f094e4442 100644 --- a/src/sed.js +++ b/src/sed.js @@ -12,9 +12,10 @@ common.register('sed', _sed, { //@ //@ ### sed([options,] search_regex, replacement, file [, file ...]) //@ ### sed([options,] search_regex, replacement, file_array) +//@ //@ Available options: //@ -//@ + `-i`: Replace contents of 'file' in-place. _Note that no backups will be created!_ +//@ + `-i`: Replace contents of `file` in-place. _Note that no backups will be created!_ //@ //@ Examples: //@ @@ -23,8 +24,8 @@ common.register('sed', _sed, { //@ sed(/.*DELETE_THIS_LINE.*\n/, '', 'source.js'); //@ ``` //@ -//@ Reads an input string from `files` and performs a JavaScript `replace()` on the input -//@ using the given search regex and replacement string or function. Returns the new string after replacement. +//@ Reads an input string from `file`s, and performs a JavaScript `replace()` on the input +//@ using the given `search_regex` and `replacement` string or function. Returns the new string after replacement. //@ //@ Note: //@ diff --git a/src/set.js b/src/set.js index 238e23e4a..1101b6ffa 100644 --- a/src/set.js +++ b/src/set.js @@ -7,6 +7,7 @@ common.register('set', _set, { //@ //@ ### set(options) +//@ //@ Available options: //@ //@ + `+/-e`: exit upon error (`config.fatal`) @@ -20,7 +21,7 @@ common.register('set', _set, { //@ set('+e'); // this undoes a "set('-e')" //@ ``` //@ -//@ Sets global configuration variables +//@ Sets global configuration variables. function _set(options) { if (!options) { var args = [].slice.call(arguments, 0); diff --git a/src/sort.js b/src/sort.js index e0feed746..0f42cb6a3 100644 --- a/src/sort.js +++ b/src/sort.js @@ -41,9 +41,10 @@ function numericalCmp(a, b) { //@ //@ ### sort([options,] file [, file ...]) //@ ### sort([options,] file_array) +//@ //@ Available options: //@ -//@ + `-r`: Reverse the result of comparisons +//@ + `-r`: Reverse the results //@ + `-n`: Compare according to numerical value //@ //@ Examples: @@ -53,8 +54,8 @@ function numericalCmp(a, b) { //@ sort('-r', 'foo.txt'); //@ ``` //@ -//@ Return the contents of the files, sorted line-by-line. Sorting multiple -//@ files mixes their content, just like unix sort does. +//@ Return the contents of the `file`s, sorted line-by-line. Sorting multiple +//@ files mixes their content (just as unix `sort` does). function _sort(options, files) { // Check if this is coming from a pipe var pipe = common.readFromPipe(); diff --git a/src/tail.js b/src/tail.js index 5e0256e76..258412f73 100644 --- a/src/tail.js +++ b/src/tail.js @@ -11,9 +11,10 @@ common.register('tail', _tail, { //@ //@ ### tail([{'-n': \},] file [, file ...]) //@ ### tail([{'-n': \},] file_array) +//@ //@ Available options: //@ -//@ + `-n `: Show the last `` lines of the files +//@ + `-n `: Show the last `` lines of `file`s //@ //@ Examples: //@ @@ -23,7 +24,7 @@ common.register('tail', _tail, { //@ var str = tail(['file1', 'file2']); // same as above //@ ``` //@ -//@ Read the end of a file. +//@ Read the end of a `file`. function _tail(options, files) { var tail = []; var pipe = common.readFromPipe(); diff --git a/src/test.js b/src/test.js index c0c6469f8..228c7471f 100644 --- a/src/test.js +++ b/src/test.js @@ -19,6 +19,7 @@ common.register('test', _test, { //@ //@ ### test(expression) +//@ //@ Available expression primaries: //@ //@ + `'-b', 'path'`: true if path is a block device @@ -37,7 +38,7 @@ common.register('test', _test, { //@ if (!test('-f', path)) continue; // skip if it's a regular file //@ ``` //@ -//@ Evaluates expression using the available primaries and returns corresponding value. +//@ Evaluates `expression` using the available primaries and returns corresponding value. function _test(options, path) { if (!path) common.error('no path given'); diff --git a/src/to.js b/src/to.js index d3d9e37be..f1355bfc7 100644 --- a/src/to.js +++ b/src/to.js @@ -17,7 +17,7 @@ common.register('to', _to, { //@ ``` //@ //@ Analogous to the redirection operator `>` in Unix, but works with -//@ ShellStrings (such as those returned by `cat`, `grep`, etc). _Like Unix +//@ `ShellStrings` (such as those returned by `cat`, `grep`, etc.). _Like Unix //@ redirections, `to()` will overwrite any existing file!_ function _to(options, file) { if (!file) common.error('wrong arguments'); diff --git a/src/toEnd.js b/src/toEnd.js index dc165fe8d..63749d0b4 100644 --- a/src/toEnd.js +++ b/src/toEnd.js @@ -17,7 +17,7 @@ common.register('toEnd', _toEnd, { //@ ``` //@ //@ Analogous to the redirect-and-append operator `>>` in Unix, but works with -//@ ShellStrings (such as those returned by `cat`, `grep`, etc). +//@ `ShellStrings` (such as those returned by `cat`, `grep`, etc.). function _toEnd(options, file) { if (!file) common.error('wrong arguments'); diff --git a/src/touch.js b/src/touch.js index dd6b8bc54..7b7033cd4 100644 --- a/src/touch.js +++ b/src/touch.js @@ -14,13 +14,14 @@ common.register('touch', _touch, { //@ //@ ### touch([options,] file [, file ...]) //@ ### touch([options,] file_array) +//@ //@ Available options: //@ //@ + `-a`: Change only the access time //@ + `-c`: Do not create any files //@ + `-m`: Change only the modification time -//@ + `-d DATE`: Parse DATE and use it instead of current time -//@ + `-r FILE`: Use FILE's times instead of current time +//@ + `-d DATE`: Parse `DATE` and use it instead of current time +//@ + `-r FILE`: Use `FILE`'s times instead of current time //@ //@ Examples: //@ @@ -30,9 +31,9 @@ common.register('touch', _touch, { //@ touch({ '-r': FILE }, '/path/to/some/dir/source.js'); //@ ``` //@ -//@ Update the access and modification times of each FILE to the current time. -//@ A FILE argument that does not exist is created empty, unless -c is supplied. -//@ This is a partial implementation of *[touch(1)](http://linux.die.net/man/1/touch)*. +//@ Update the access and modification times of each `FILE` to the current time. +//@ A `FILE` argument that does not exist is created empty, unless `-c` is supplied. +//@ This is a partial implementation of [`touch(1)`](http://linux.die.net/man/1/touch). function _touch(opts, files) { if (!files) { common.error('no files given'); diff --git a/src/uniq.js b/src/uniq.js index 2a287ce15..a7e343bd3 100644 --- a/src/uniq.js +++ b/src/uniq.js @@ -21,6 +21,7 @@ common.register('uniq', _uniq, { //@ //@ ### uniq([options,] [input, [output]]) +//@ //@ Available options: //@ //@ + `-i`: Ignore case while comparing @@ -35,7 +36,7 @@ common.register('uniq', _uniq, { //@ uniq('-cd', 'foo.txt', 'bar.txt'); //@ ``` //@ -//@ Filter adjacent matching lines from input +//@ Filter adjacent matching lines from `input`. function _uniq(options, input, output) { // Check if this is coming from a pipe var pipe = common.readFromPipe(); diff --git a/src/which.js b/src/which.js index e6ae9eb58..0e5433c03 100644 --- a/src/which.js +++ b/src/which.js @@ -9,11 +9,11 @@ common.register('which', _which, { }, }); -// XP's system default value for PATHEXT system variable, just in case it's not +// XP's system default value for `PATHEXT` system variable, just in case it's not // set on Windows. var XP_DEFAULT_PATHEXT = '.com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh'; -// Cross-platform method for splitting environment PATH variables +// Cross-platform method for splitting environment `PATH` variables function splitPath(p) { return p ? p.split(path.delimiter) : []; } @@ -31,9 +31,9 @@ function checkPath(pathName) { //@ var nodeExec = which('node'); //@ ``` //@ -//@ Searches for `command` in the system's PATH. On Windows, this uses the +//@ Searches for `command` in the system's `PATH`. On Windows, this uses the //@ `PATHEXT` variable to append the extension if it's not already executable. -//@ Returns string containing the absolute path to the command. +//@ Returns string containing the absolute path to `command`. function _which(options, cmd) { if (!cmd) common.error('must specify command'); From d7b6a1f3784fa6f9d1abcc07fcec6d08e89bf294 Mon Sep 17 00:00:00 2001 From: Tzu-Lin Huang Date: Tue, 24 Apr 2018 03:24:29 +0900 Subject: [PATCH 45/71] Workaround codecov bug of miscalculation of coverage (#795) (#838) This fixes #795 (actually, workarounds it.) For detail, please refer to the issue. --- src/ls.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ls.js b/src/ls.js index eea99c5ca..daebdf822 100644 --- a/src/ls.js +++ b/src/ls.js @@ -79,6 +79,10 @@ function _ls(options, paths) { stat = options.link ? common.statFollowLinks(p) : common.statNoFollowLinks(p); // follow links to directories by default if (stat.isSymbolicLink()) { + /* istanbul ignore next */ + // workaround for https://github.com/shelljs/shelljs/issues/795 + // codecov seems to have a bug that miscalculate this block as uncovered. + // but according to nyc report this block does get covered. try { var _stat = common.statFollowLinks(p); if (_stat.isDirectory()) { From 3ce805e6363fa2d067d9d4c9a9d935e5b62ead30 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 7 May 2018 23:59:38 -0700 Subject: [PATCH 46/71] docs(changelog): updated by Nate Fischer [ci skip] --- CHANGELOG.md | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89409338a..a6f6270a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,34 @@ # Change Log +## [Unreleased](https://github.com/shelljs/shelljs/tree/HEAD) + +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.8.1...HEAD) + +**Closed issues:** + +- High severity vulnerability in shelljs 0.8.1 [\#842](https://github.com/shelljs/shelljs/issues/842) +- Add test for ls\(\) on a symlink to a directory [\#795](https://github.com/shelljs/shelljs/issues/795) +- Harden shell.exec by writing the child process in a source file [\#782](https://github.com/shelljs/shelljs/issues/782) +- shell.exec\(\) doesn't respond correctly to config.fatal = true [\#735](https://github.com/shelljs/shelljs/issues/735) +- Merge 'exec: internal error' with ShellJSInternalError [\#734](https://github.com/shelljs/shelljs/issues/734) +- exec returning null from command [\#724](https://github.com/shelljs/shelljs/issues/724) +- Only Get Stderr from Exec [\#371](https://github.com/shelljs/shelljs/issues/371) +- Execute child.stdout.on before child.on\("exit"\) [\#224](https://github.com/shelljs/shelljs/issues/224) + +**Merged pull requests:** + +- Workaround codecov bug of miscalculation of coverage \(\#795\) [\#838](https://github.com/shelljs/shelljs/pull/838) ([dwi2](https://github.com/dwi2)) +- Update doc comments and regenerate README.md. [\#825](https://github.com/shelljs/shelljs/pull/825) ([Zearin](https://github.com/Zearin)) +- chore: update contributing guidelines [\#817](https://github.com/shelljs/shelljs/pull/817) ([nfischer](https://github.com/nfischer)) +- chore\(lint\): don't allow excess trailing newlines [\#816](https://github.com/shelljs/shelljs/pull/816) ([nfischer](https://github.com/nfischer)) +- Remove separate "internal error" from exec [\#802](https://github.com/shelljs/shelljs/pull/802) ([freitagbr](https://github.com/freitagbr)) + ## [v0.8.1](https://github.com/shelljs/shelljs/tree/v0.8.1) (2018-01-20) [Full Changelog](https://github.com/shelljs/shelljs/compare/v0.8.0...v0.8.1) **Closed issues:** - Exec failing with internal error when piping large output [\#818](https://github.com/shelljs/shelljs/issues/818) -- Shelljs exec\(\) not executing variables [\#815](https://github.com/shelljs/shelljs/issues/815) -- support for node-0.10.\* is broken [\#814](https://github.com/shelljs/shelljs/issues/814) - using sed to replace just the first occurrence of a string [\#813](https://github.com/shelljs/shelljs/issues/813) **Merged pull requests:** @@ -794,6 +815,7 @@ - exec with callback should automatically be async [\#31](https://github.com/shelljs/shelljs/issues/31) - Exporting variables. [\#30](https://github.com/shelljs/shelljs/issues/30) - Detecting shelljs/node [\#27](https://github.com/shelljs/shelljs/issues/27) +- Unexpected cp behaviour with directories [\#15](https://github.com/shelljs/shelljs/issues/15) **Merged pull requests:** @@ -808,7 +830,6 @@ - gh-pages: clicking 'fork me' just reloads the page [\#26](https://github.com/shelljs/shelljs/issues/26) - Not declared local var implies possible memory leak [\#21](https://github.com/shelljs/shelljs/issues/21) - Cannot echo a string that starts with - [\#20](https://github.com/shelljs/shelljs/issues/20) -- Unexpected cp behaviour with directories [\#15](https://github.com/shelljs/shelljs/issues/15) **Merged pull requests:** From 3b266d0a2992f5bbae5ec03710c9e29b1175e67a Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 8 May 2018 00:09:33 -0700 Subject: [PATCH 47/71] 0.8.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e22598d11..738b722e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.8.1", + "version": "0.8.2", "description": "Portable Unix shell commands for Node.js", "keywords": [ "shelljs", From 97a4df82a0a0ba5275bef54c18e408d24941bcb0 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 8 May 2018 00:29:11 -0700 Subject: [PATCH 48/71] docs(changelog): updated by Nate Fischer [ci skip] --- CHANGELOG.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6f6270a6..15741bc80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,7 @@ # Change Log -## [Unreleased](https://github.com/shelljs/shelljs/tree/HEAD) - -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.8.1...HEAD) +## [v0.8.2](https://github.com/shelljs/shelljs/tree/v0.8.2) (2018-05-08) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.8.1...v0.8.2) **Closed issues:** @@ -815,7 +814,6 @@ - exec with callback should automatically be async [\#31](https://github.com/shelljs/shelljs/issues/31) - Exporting variables. [\#30](https://github.com/shelljs/shelljs/issues/30) - Detecting shelljs/node [\#27](https://github.com/shelljs/shelljs/issues/27) -- Unexpected cp behaviour with directories [\#15](https://github.com/shelljs/shelljs/issues/15) **Merged pull requests:** @@ -830,6 +828,7 @@ - gh-pages: clicking 'fork me' just reloads the page [\#26](https://github.com/shelljs/shelljs/issues/26) - Not declared local var implies possible memory leak [\#21](https://github.com/shelljs/shelljs/issues/21) - Cannot echo a string that starts with - [\#20](https://github.com/shelljs/shelljs/issues/20) +- Unexpected cp behaviour with directories [\#15](https://github.com/shelljs/shelljs/issues/15) **Merged pull requests:** From dd5551da0c8da3a14de7c492865d1dfb4defada4 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 8 May 2018 21:30:32 -0700 Subject: [PATCH 49/71] chore: update shelljs-release version (#846) This bumps the version of our dependency, shelljs-release. I just cut the 3.0 release for shelljs-release, which contains support for the `--otp` flag, as well as the significant refactoring work we put in. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 738b722e9..9fd41b6e2 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "eslint-plugin-import": "^1.11.1", "nyc": "^11.3.0", "shelljs-changelog": "^0.2.0", - "shelljs-release": "^0.2.0", + "shelljs-release": "^0.3.0", "shx": "^0.2.0", "travis-check-changes": "^0.2.0" }, From 4733a32c0825cd75742959ebcef7dc93b03f1b50 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Wed, 9 May 2018 17:02:37 -0700 Subject: [PATCH 50/71] chore(appveyor): do not use latest npm (#847) This changes appveyor from using the latest npm version to only using the preinstalled npm version. This is safer, because it's guaranteed to be a compatible version. Fixes #844 --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 3c7952800..f66b81748 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,7 +12,6 @@ version: '{build}' # Install scripts. (runs after repo cloning) install: - ps: Install-Product node $env:nodejs_version - - npm -g install npm@latest - set PATH=%APPDATA%\npm;%PATH% - node --version - npm --version From aa9d443e7b8126763cfb76b1230a7bdb578a6a5e Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 10 May 2018 21:16:25 -0700 Subject: [PATCH 51/71] chore: output npm version in travis (#850) Knowing the `npm` version was a huge help to debugging issue #844. For some reason, we output this on appveyor but not on Travis. This PR fixes that. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 02a02fa5c..bb164d863 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ install: - source ~/.nvm/nvm.sh - nvm install $NODE_VERSION - node --version + - npm --version - npm install os: - linux From 93bbf684c6f487b8ff65b3fc39cde13020f02896 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Wed, 27 Jun 2018 00:02:32 -0700 Subject: [PATCH 52/71] Prevent require-ing bin/shjs (#848) * Prevent require-ing bin/shjs * Move require guard up, and improve function name * Move require up and clarify comment --- bin/shjs | 19 ++++++++++++++----- test/shjs.js | 11 ++++++++++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/bin/shjs b/bin/shjs index 75ca58b9d..c4609f7af 100755 --- a/bin/shjs +++ b/bin/shjs @@ -1,12 +1,23 @@ #!/usr/bin/env node + +if (require.main !== module) { + throw new Error('Executable-only module should not be required'); +} + +// we must import global ShellJS methods after the require.main check to prevent the global +// namespace from being polluted if the error is caught require('../global'); -if (process.argv.length < 3) { - console.log('ShellJS: missing argument (script name)'); +function exitWithErrorMessage(msg) { + console.log(msg); console.log(); process.exit(1); } +if (process.argv.length < 3) { + exitWithErrorMessage('ShellJS: missing argument (script name)'); +} + var args, scriptName = process.argv[2]; env['NODE_PATH'] = __dirname + '/../..'; @@ -19,9 +30,7 @@ if (!scriptName.match(/\.js/) && !scriptName.match(/\.coffee/)) { } if (!test('-f', scriptName)) { - console.log('ShellJS: script not found ('+scriptName+')'); - console.log(); - process.exit(1); + exitWithErrorMessage('ShellJS: script not found ('+scriptName+')'); } args = process.argv.slice(3); diff --git a/test/shjs.js b/test/shjs.js index 4df91666d..850a60f93 100644 --- a/test/shjs.js +++ b/test/shjs.js @@ -4,9 +4,10 @@ import test from 'ava'; import shell from '..'; +const binPath = path.resolve(__dirname, '../bin/shjs'); + function runWithShjs(name) { // prefix with 'node ' for Windows, don't prefix for unix - const binPath = path.resolve(__dirname, '../bin/shjs'); const execPath = process.platform === 'win32' ? `${JSON.stringify(shell.config.execPath)} ` : ''; @@ -52,3 +53,11 @@ test('Extension detection', t => { t.is(result.stdout, 'OK!\n'); t.falsy(result.stderr); }); + +// +// Invalids +// + +test('disallow require-ing', t => { + t.throws(() => require(binPath), 'Executable-only module should not be required'); +}); From 72ff790f4ffbc66f2583f3e3be95d9fd350a4f5f Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 28 Jun 2018 14:15:38 -0700 Subject: [PATCH 53/71] chore: bump dev dependencies and add package-lock (#864) No change to logic. This reduces install spam by bumping codecov to avoid depending on a deprecated graceful-fs version, as well as adding a package-lock.json. --- package-lock.json | 7520 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 7521 insertions(+), 1 deletion(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..f2ebfb5cd --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7520 @@ +{ + "name": "shelljs", + "version": "0.8.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@ava/babel-plugin-throws-helper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ava/babel-plugin-throws-helper/-/babel-plugin-throws-helper-2.0.0.tgz", + "integrity": "sha1-L8H+PCEacQcaTsp7j3r1hCzRrnw=", + "dev": true + }, + "@ava/babel-preset-stage-4": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@ava/babel-preset-stage-4/-/babel-preset-stage-4-1.1.0.tgz", + "integrity": "sha512-oWqTnIGXW3k72UFidXzW0ONlO7hnO9x02S/QReJ7NBGeiBH9cUHY9+EfV6C8PXC6YJH++WrliEq03wMSJGNZFg==", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-syntax-trailing-function-commas": "6.22.0", + "babel-plugin-transform-async-to-generator": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-exponentiation-operator": "6.24.1", + "package-hash": "1.2.0" + }, + "dependencies": { + "md5-hex": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", + "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", + "dev": true, + "requires": { + "md5-o-matic": "0.1.1" + } + }, + "package-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-1.2.0.tgz", + "integrity": "sha1-AD5WzVe3NqbtYRTMK4FUJnJ3DkQ=", + "dev": true, + "requires": { + "md5-hex": "1.3.0" + } + } + } + }, + "@ava/babel-preset-transform-test-files": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@ava/babel-preset-transform-test-files/-/babel-preset-transform-test-files-3.0.0.tgz", + "integrity": "sha1-ze0RlqjY2TgaUJJAq5LpGl7Aafc=", + "dev": true, + "requires": { + "@ava/babel-plugin-throws-helper": "2.0.0", + "babel-plugin-espower": "2.4.0" + } + }, + "@ava/write-file-atomic": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ava/write-file-atomic/-/write-file-atomic-2.2.0.tgz", + "integrity": "sha512-BTNB3nGbEfJT+69wuqXFr/bQH7Vr7ihx2xGOMNqPgDGhwspoZhiWumDDZNjBy7AScmqS5CELIOGtPVXESyrnDA==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + }, + "@concordance/react": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@concordance/react/-/react-1.0.0.tgz", + "integrity": "sha512-htrsRaQX8Iixlsek8zQU7tE8wcsTQJ5UhZkSPEA8slCDAisKpC/2VgU/ucPn32M5/LjGGXRaUEKvEw1Wiuu4zQ==", + "dev": true, + "requires": { + "arrify": "1.0.1" + } + }, + "acorn": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", + "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + }, + "ansi-align": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, + "requires": { + "string-width": "2.1.1" + } + }, + "ansi-escapes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz", + "integrity": "sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.2" + } + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", + "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=", + "dev": true + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-exclude": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/arr-exclude/-/arr-exclude-1.0.0.tgz", + "integrity": "sha1-38fC5VKicHI8zaBM8xKMjL/lxjE=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "auto-bind": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-1.2.1.tgz", + "integrity": "sha512-/W9yj1yKmBLwpexwAujeD9YHwYmRuWFGV8HWE7smQab797VeHa4/cnE2NFeDhA+E+5e/OGBI8763EhLjfZ/MXA==", + "dev": true + }, + "ava": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/ava/-/ava-0.21.0.tgz", + "integrity": "sha512-+ZjahyjqyzkPLlFZe2OoLmiE3aaQ2jK5h74wrkuX5I+J6LpNAPoQ8X/EhqEtKEjuWwmniLAjnVjZ7OY8rWdJwA==", + "dev": true, + "requires": { + "@ava/babel-preset-stage-4": "1.1.0", + "@ava/babel-preset-transform-test-files": "3.0.0", + "@ava/write-file-atomic": "2.2.0", + "@concordance/react": "1.0.0", + "ansi-escapes": "2.0.0", + "ansi-styles": "3.2.1", + "arr-flatten": "1.1.0", + "array-union": "1.0.2", + "array-uniq": "1.0.3", + "arrify": "1.0.1", + "auto-bind": "1.2.1", + "ava-init": "0.2.1", + "babel-core": "6.26.3", + "bluebird": "3.5.1", + "caching-transform": "1.0.1", + "chalk": "2.4.1", + "chokidar": "1.7.0", + "clean-stack": "1.3.0", + "clean-yaml-object": "0.1.0", + "cli-cursor": "2.1.0", + "cli-spinners": "1.3.1", + "cli-truncate": "1.1.0", + "co-with-promise": "4.6.0", + "code-excerpt": "2.1.1", + "common-path-prefix": "1.0.0", + "concordance": "3.0.0", + "convert-source-map": "1.5.1", + "core-assert": "0.2.1", + "currently-unhandled": "0.4.1", + "debug": "2.6.9", + "dot-prop": "4.2.0", + "empower-core": "0.6.2", + "equal-length": "1.0.1", + "figures": "2.0.0", + "find-cache-dir": "1.0.0", + "fn-name": "2.0.1", + "get-port": "3.2.0", + "globby": "6.1.0", + "has-flag": "2.0.0", + "hullabaloo-config-manager": "1.1.1", + "ignore-by-default": "1.0.1", + "import-local": "0.1.1", + "indent-string": "3.2.0", + "is-ci": "1.1.0", + "is-generator-fn": "1.0.0", + "is-obj": "1.0.1", + "is-observable": "0.2.0", + "is-promise": "2.1.0", + "js-yaml": "3.12.0", + "last-line-stream": "1.0.0", + "lodash.clonedeepwith": "4.5.0", + "lodash.debounce": "4.0.8", + "lodash.difference": "4.5.0", + "lodash.flatten": "4.4.0", + "loud-rejection": "1.6.0", + "make-dir": "1.3.0", + "matcher": "1.1.1", + "md5-hex": "2.0.0", + "meow": "3.7.0", + "ms": "2.1.1", + "multimatch": "2.1.0", + "observable-to-promise": "0.5.0", + "option-chain": "1.0.0", + "package-hash": "2.0.0", + "pkg-conf": "2.1.0", + "plur": "2.1.2", + "pretty-ms": "2.1.0", + "require-precompiled": "0.1.0", + "resolve-cwd": "2.0.0", + "safe-buffer": "5.1.2", + "slash": "1.0.0", + "source-map-support": "0.4.18", + "stack-utils": "1.0.1", + "strip-ansi": "4.0.0", + "strip-bom-buf": "1.0.0", + "supports-color": "4.5.0", + "time-require": "0.1.2", + "trim-off-newlines": "1.0.1", + "unique-temp-dir": "1.0.0", + "update-notifier": "2.5.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + } + } + }, + "ava-init": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ava-init/-/ava-init-0.2.1.tgz", + "integrity": "sha512-lXwK5LM+2g1euDRqW1mcSX/tqzY1QU7EjKpqayFPPtNRmbSYZ8RzPO5tqluTToijmtjp2M+pNpVdbcHssC4glg==", + "dev": true, + "requires": { + "arr-exclude": "1.0.0", + "execa": "0.7.0", + "has-yarn": "1.0.0", + "read-pkg-up": "2.0.0", + "write-pkg": "3.2.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.1", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.1", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.10", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + } + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "dev": true, + "requires": { + "babel-helper-explode-assignable-expression": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.10" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-espower": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-espower/-/babel-plugin-espower-2.4.0.tgz", + "integrity": "sha512-/+SRpy7pKgTI28oEHfn1wkuM5QFAdRq8WNsOOih1dVrdV6A/WbNbRZyl0eX5eyDgtb0lOE27PeDFuCX2j8OxVg==", + "dev": true, + "requires": { + "babel-generator": "6.26.1", + "babylon": "6.18.0", + "call-matcher": "1.0.1", + "core-js": "2.5.7", + "espower-location-detector": "1.0.0", + "espurify": "1.8.0", + "estraverse": "4.2.0" + } + }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "dev": true + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "dev": true + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "dev": true + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "6.24.1", + "babel-plugin-syntax-async-functions": "6.13.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "dev": true, + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "6.24.1", + "babel-plugin-syntax-exponentiation-operator": "6.13.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "6.26.3", + "babel-runtime": "6.26.0", + "core-js": "2.5.7", + "home-or-tmp": "2.0.0", + "lodash": "4.17.10", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.7", + "regenerator-runtime": "0.11.1" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.10" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.10" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.10", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "binary-extensions": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "dev": true + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true + }, + "boxen": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "dev": true, + "requires": { + "ansi-align": "2.0.0", + "camelcase": "4.1.0", + "chalk": "2.4.1", + "cli-boxes": "1.0.0", + "string-width": "2.1.1", + "term-size": "1.2.0", + "widest-line": "2.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "buf-compare": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buf-compare/-/buf-compare-1.0.1.tgz", + "integrity": "sha1-/vKNqLgROgoNtEMLC2Rntpcws0o=", + "dev": true + }, + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caching-transform": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", + "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", + "dev": true, + "requires": { + "md5-hex": "1.3.0", + "mkdirp": "0.5.1", + "write-file-atomic": "1.3.4" + }, + "dependencies": { + "md5-hex": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", + "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", + "dev": true, + "requires": { + "md5-o-matic": "0.1.1" + } + }, + "write-file-atomic": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + } + } + }, + "call-matcher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-matcher/-/call-matcher-1.0.1.tgz", + "integrity": "sha1-UTTQd5hPcSpU2tPL9i3ijc5BbKg=", + "dev": true, + "requires": { + "core-js": "2.5.7", + "deep-equal": "1.0.1", + "espurify": "1.8.0", + "estraverse": "4.2.0" + } + }, + "call-signature": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/call-signature/-/call-signature-0.0.2.tgz", + "integrity": "sha1-qEq8glpV70yysCi9dOIFpluaSZY=", + "dev": true + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "capture-stack-trace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", + "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "ci-info": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz", + "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==", + "dev": true + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "clean-stack": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", + "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE=", + "dev": true + }, + "clean-yaml-object": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", + "integrity": "sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=", + "dev": true + }, + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-spinners": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz", + "integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==", + "dev": true + }, + "cli-truncate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-1.1.0.tgz", + "integrity": "sha512-bAtZo0u82gCfaAGfSNxUdTI9mNyza7D8w4CVCcaOsy7sgwDzvx6ekr6cuWJqY3UGzgnQ1+4wgENup5eIhgxEYA==", + "dev": true, + "requires": { + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "co-with-promise": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co-with-promise/-/co-with-promise-4.6.0.tgz", + "integrity": "sha1-QT59tvWJOmC5Qs9JLEvsk9tBWrc=", + "dev": true, + "requires": { + "pinkie-promise": "1.0.0" + } + }, + "code-excerpt": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-2.1.1.tgz", + "integrity": "sha512-tJLhH3EpFm/1x7heIW0hemXJTUU5EWl2V0EIX558jp05Mt1U6DVryCgkp3l37cxqs+DNbNgxG43SkwJXpQ14Jw==", + "dev": true, + "requires": { + "convert-to-spaces": "1.0.2" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "codecov": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.0.2.tgz", + "integrity": "sha512-9ljtIROIjPIUmMRqO+XuDITDoV8xRrZmA0jcEq6p2hg2+wY9wGmLfreAZGIL72IzUfdEDZaU8+Vjidg1fBQ8GQ==", + "dev": true, + "requires": { + "argv": "0.0.2", + "request": "2.87.0", + "urlgrey": "0.4.4" + } + }, + "coffee-script": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", + "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", + "dev": true + }, + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "dev": true, + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", + "dev": true + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "common-path-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-1.0.0.tgz", + "integrity": "sha1-zVL28HEuC6q5fW+XModPIvR3UsA=", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "1.1.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, + "concordance": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/concordance/-/concordance-3.0.0.tgz", + "integrity": "sha512-CZBzJ3/l5QJjlZM20WY7+5GP5pMTw+1UEbThcpMw8/rojsi5sBCiD8ZbBLtD+jYpRGAkwuKuqk108c154V9eyQ==", + "dev": true, + "requires": { + "date-time": "2.1.0", + "esutils": "2.0.2", + "fast-diff": "1.1.2", + "function-name-support": "0.2.0", + "js-string-escape": "1.0.1", + "lodash.clonedeep": "4.5.0", + "lodash.flattendeep": "4.4.0", + "lodash.merge": "4.6.1", + "md5-hex": "2.0.0", + "semver": "5.5.0", + "well-known-symbols": "1.0.0" + } + }, + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, + "requires": { + "dot-prop": "4.2.0", + "graceful-fs": "4.1.11", + "make-dir": "1.3.0", + "unique-string": "1.0.0", + "write-file-atomic": "2.3.0", + "xdg-basedir": "3.0.0" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "convert-source-map": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", + "dev": true + }, + "convert-to-spaces": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-1.0.2.tgz", + "integrity": "sha1-fj5Iu+bZl7FBfdyihoIEtNPYVxU=", + "dev": true + }, + "core-assert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/core-assert/-/core-assert-0.2.1.tgz", + "integrity": "sha1-+F4s+b/tKPdzzIs/pcW2m9wC/j8=", + "dev": true, + "requires": { + "buf-compare": "1.0.1", + "is-error": "2.2.1" + } + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "requires": { + "capture-stack-trace": "1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "1.0.2" + } + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "0.10.45" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "date-time": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-2.1.0.tgz", + "integrity": "sha512-/9+C44X7lot0IeiyfgJmETtRMhBidBYM2QFFIkGa0U1k+hSyY87Nw7PY3eDqpvCBm7I3WCSfPeZskW/YYq6m4g==", + "dev": true, + "requires": { + "time-zone": "1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + }, + "dependencies": { + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "1.0.1" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "empower-core": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/empower-core/-/empower-core-0.6.2.tgz", + "integrity": "sha1-Wt71ZgiOMfuoC6CjbfR9cJQWkUQ=", + "dev": true, + "requires": { + "call-signature": "0.0.2", + "core-js": "2.5.7" + } + }, + "equal-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/equal-length/-/equal-length-1.0.1.tgz", + "integrity": "sha1-IcoRLUirJLTh5//A5TOdMf38J0w=", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es5-ext": { + "version": "0.10.45", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz", + "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", + "dev": true, + "requires": { + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1", + "next-tick": "1.0.0" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.45", + "es6-symbol": "3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.45", + "es6-iterator": "2.0.3", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "dev": true + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.45", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.45" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.45", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz", + "integrity": "sha1-5MyPoPAJ+4KaquI4VaKTYL4fbBE=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "concat-stream": "1.6.2", + "debug": "2.6.9", + "doctrine": "1.5.0", + "es6-map": "0.1.5", + "escope": "3.6.0", + "espree": "3.5.4", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "1.3.1", + "glob": "7.1.2", + "globals": "9.18.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "0.12.0", + "is-my-json-valid": "2.17.2", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "mkdirp": "0.5.1", + "optionator": "0.8.2", + "path-is-absolute": "1.0.1", + "path-is-inside": "1.0.2", + "pluralize": "1.2.1", + "progress": "1.1.8", + "require-uncached": "1.0.3", + "shelljs": "0.6.1", + "strip-json-comments": "1.0.4", + "table": "3.8.3", + "text-table": "0.2.0", + "user-home": "2.0.0" + }, + "dependencies": { + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + } + } + }, + "eslint-config-airbnb-base": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-3.0.1.tgz", + "integrity": "sha1-t3fgH2XpRpM0QrSZ/IUYqiUaZTA=", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz", + "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=", + "dev": true, + "requires": { + "debug": "2.6.9", + "object-assign": "4.1.1", + "resolve": "1.8.1" + } + }, + "eslint-plugin-import": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-1.16.0.tgz", + "integrity": "sha1-svoH68xTUE0PKkR3WC7Iv/GHG58=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1", + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.3.0", + "es6-map": "0.1.5", + "es6-set": "0.1.5", + "eslint-import-resolver-node": "0.2.3", + "has": "1.0.3", + "lodash.cond": "4.5.2", + "lodash.endswith": "4.2.1", + "lodash.find": "4.6.0", + "lodash.findindex": "4.6.0", + "minimatch": "3.0.4", + "object-assign": "4.1.1", + "pkg-dir": "1.0.0", + "pkg-up": "1.0.0" + }, + "dependencies": { + "doctrine": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.3.0.tgz", + "integrity": "sha1-E+dWgrVVGEJCdvfBc3g0Vu+RPSY=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "1.1.2" + } + } + } + }, + "espower-location-detector": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/espower-location-detector/-/espower-location-detector-1.0.0.tgz", + "integrity": "sha1-oXt+zFnTDheeK+9z+0E3cEyzMbU=", + "dev": true, + "requires": { + "is-url": "1.2.4", + "path-is-absolute": "1.0.1", + "source-map": "0.5.7", + "xtend": "4.0.1" + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "5.7.1", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "espurify": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/espurify/-/espurify-1.8.0.tgz", + "integrity": "sha512-jdkJG9jswjKCCDmEridNUuIQei9algr+o66ZZ19610ZoBsiWLRsQGNYS4HGez3Z/DsR0lhANGAqiwBUclPuNag==", + "dev": true, + "requires": { + "core-js": "2.5.7" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.45" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "2.2.4" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "fast-diff": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", + "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz", + "integrity": "sha1-RMYepgeuS+nBQC9B9EJwy/4zT/g=", + "dev": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "3.0.0", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "1.0.1", + "make-dir": "1.3.0", + "pkg-dir": "2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "dev": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "fn-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", + "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function-name-support": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/function-name-support/-/function-name-support-0.2.0.tgz", + "integrity": "sha1-VdO/qm6v1QWlD5vIH99XVkoLsHE=", + "dev": true + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "1.0.2" + } + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "1.3.5" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + } + } + }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "requires": { + "create-error-class": "3.0.2", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "is-redirect": "1.0.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "lowercase-keys": "1.0.1", + "safe-buffer": "5.1.2", + "timed-out": "4.0.1", + "unzip-response": "2.0.1", + "url-parse-lax": "1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.5.2", + "har-schema": "2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "has-yarn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-1.0.0.tgz", + "integrity": "sha1-ieJdtgS3Jcj1l2//Ct3JIbgopac=", + "dev": true + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", + "integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.2" + } + }, + "hullabaloo-config-manager": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/hullabaloo-config-manager/-/hullabaloo-config-manager-1.1.1.tgz", + "integrity": "sha512-ztKnkZV0TmxnumCDHHgLGNiDnotu4EHCp9YMkznWuo4uTtCyJ+cu+RNcxUeXYKTllpvLFWnbfWry09yzszgg+A==", + "dev": true, + "requires": { + "dot-prop": "4.2.0", + "es6-error": "4.1.1", + "graceful-fs": "4.1.11", + "indent-string": "3.2.0", + "json5": "0.5.1", + "lodash.clonedeep": "4.5.0", + "lodash.clonedeepwith": "4.5.0", + "lodash.isequal": "4.5.0", + "lodash.merge": "4.6.1", + "md5-hex": "2.0.0", + "package-hash": "2.0.0", + "pkg-dir": "2.0.0", + "resolve-from": "3.0.0", + "safe-buffer": "5.1.2" + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "import-local": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-0.1.1.tgz", + "integrity": "sha1-sReVcqrNwRxqkQCftDDbyrX2aKg=", + "dev": true, + "requires": { + "pkg-dir": "2.0.0", + "resolve-cwd": "2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "ansi-regex": "2.1.1", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.2.0", + "figures": "1.7.0", + "lodash": "4.17.10", + "readline2": "1.0.1", + "run-async": "0.1.0", + "rx-lite": "3.1.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "irregular-plurals": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.4.0.tgz", + "integrity": "sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "1.11.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-ci": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz", + "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==", + "dev": true, + "requires": { + "ci-info": "1.1.3" + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-error": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.1.tgz", + "integrity": "sha1-aEqW2EB2V3yY9M20DG0mpRI78Zw=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-generator-fn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", + "integrity": "sha1-lp1J4bszKfa7fwkIm+JleLLd1Go=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "0.1.1", + "is-path-inside": "1.0.1" + } + }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "dev": true + }, + "is-my-json-valid": { + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", + "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "dev": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "is-my-ip-valid": "1.0.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-npm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "dev": true + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-observable": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-0.2.0.tgz", + "integrity": "sha1-s2ExHYPG5dcmyr9eJQsCNxBvWuI=", + "dev": true, + "requires": { + "symbol-observable": "0.2.4" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + }, + "last-line-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/last-line-stream/-/last-line-stream-1.0.0.tgz", + "integrity": "sha1-0bZNafhv8kry0EiDos7uFFIKVgA=", + "dev": true, + "requires": { + "through2": "2.0.3" + } + }, + "latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, + "requires": { + "package-json": "4.0.1" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.clonedeepwith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeepwith/-/lodash.clonedeepwith-4.5.0.tgz", + "integrity": "sha1-buMFc6A6GmDWcKYu8zwQzxr9vdQ=", + "dev": true + }, + "lodash.cond": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", + "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "dev": true + }, + "lodash.endswith": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.endswith/-/lodash.endswith-4.2.1.tgz", + "integrity": "sha1-/tWawXOO0+I27dcGTsRWRIs3vAk=", + "dev": true + }, + "lodash.find": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", + "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=", + "dev": true + }, + "lodash.findindex": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.findindex/-/lodash.findindex-4.6.0.tgz", + "integrity": "sha1-oyRd7mH7m24GJLU1ElYku2nBEQY=", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "matcher": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", + "integrity": "sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "math-random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "dev": true + }, + "md5-hex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz", + "integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=", + "dev": true, + "requires": { + "md5-o-matic": "0.1.1" + } + }, + "md5-o-matic": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", + "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", + "dev": true + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + } + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + } + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "1.33.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "dev": true, + "requires": { + "array-differ": "1.0.0", + "array-union": "1.0.2", + "arrify": "1.0.1", + "minimatch": "3.0.4" + } + }, + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.6.1", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "2.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nyc": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.9.0.tgz", + "integrity": "sha512-w8OdJAhXL5izerzZMdqzYKMj/pgHJyY3qEPYBjLLxrhcVoHEY9pU5ENIiZyCgG9OR7x3VcUMoD40o6PtVpfR4g==", + "dev": true, + "requires": { + "archy": "1.0.0", + "arrify": "1.0.1", + "caching-transform": "1.0.1", + "convert-source-map": "1.5.1", + "debug-log": "1.0.1", + "default-require-extensions": "1.0.0", + "find-cache-dir": "0.1.1", + "find-up": "2.1.0", + "foreground-child": "1.5.6", + "glob": "7.1.2", + "istanbul-lib-coverage": "1.2.0", + "istanbul-lib-hook": "1.1.0", + "istanbul-lib-instrument": "1.10.1", + "istanbul-lib-report": "1.1.3", + "istanbul-lib-source-maps": "1.2.3", + "istanbul-reports": "1.4.0", + "md5-hex": "1.3.0", + "merge-source-map": "1.1.0", + "micromatch": "3.1.10", + "mkdirp": "0.5.1", + "resolve-from": "2.0.0", + "rimraf": "2.6.2", + "signal-exit": "3.0.2", + "spawn-wrap": "1.4.2", + "test-exclude": "4.2.1", + "yargs": "11.1.0", + "yargs-parser": "8.1.0" + }, + "dependencies": { + "align-text": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "append-transform": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "requires": { + "default-require-extensions": "1.0.0" + } + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "async": { + "version": "1.5.2", + "bundled": true, + "dev": true + }, + "atob": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-generator": { + "version": "6.26.1", + "bundled": true, + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.10", + "source-map": "0.5.7", + "trim-right": "1.0.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "core-js": "2.5.6", + "regenerator-runtime": "0.11.1" + } + }, + "babel-template": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.10" + } + }, + "babel-traverse": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.10" + } + }, + "babel-types": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.10", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "base": { + "version": "0.11.2", + "bundled": true, + "dev": true, + "requires": { + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "requires": { + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.2", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "caching-transform": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "md5-hex": "1.3.0", + "mkdirp": "0.5.1", + "write-file-atomic": "1.3.4" + } + }, + "camelcase": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true + }, + "center-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "class-utils": { + "version": "0.3.6", + "bundled": true, + "dev": true, + "requires": { + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "cliui": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "map-visit": "1.0.0", + "object-visit": "1.0.1" + } + }, + "commondir": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "convert-source-map": { + "version": "1.5.1", + "bundled": true, + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "core-js": { + "version": "2.5.6", + "bundled": true, + "dev": true + }, + "cross-spawn": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "4.1.3", + "which": "1.3.0" + } + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debug-log": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "strip-bom": "2.0.0" + } + }, + "define-property": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "1.0.2", + "isobject": "3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "detect-indent": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true, + "dev": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "requires": { + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "fill-range": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "find-cache-dir": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "requires": { + "commondir": "1.0.1", + "mkdirp": "0.5.1", + "pkg-dir": "1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "for-in": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "foreground-child": { + "version": "1.5.6", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "4.0.2", + "signal-exit": "3.0.2" + } + }, + "fragment-cache": { + "version": "0.2.1", + "bundled": true, + "dev": true, + "requires": { + "map-cache": "0.2.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "get-caller-file": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "get-value": { + "version": "2.0.6", + "bundled": true, + "dev": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "9.18.0", + "bundled": true, + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "bundled": true, + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "bundled": true, + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "has-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "has-values": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "hosted-git-info": { + "version": "2.6.0", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "invariant": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "bundled": true, + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-odd": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-number": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "bundled": true, + "dev": true + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "istanbul-lib-coverage": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "append-transform": "0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.10.1", + "bundled": true, + "dev": true, + "requires": { + "babel-generator": "6.26.1", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.2.0", + "semver": "5.5.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "istanbul-lib-coverage": "1.2.0", + "mkdirp": "0.5.1", + "path-parse": "1.0.5", + "supports-color": "3.2.3" + }, + "dependencies": { + "supports-color": { + "version": "3.2.3", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.3", + "bundled": true, + "dev": true, + "requires": { + "debug": "3.1.0", + "istanbul-lib-coverage": "1.2.0", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "source-map": "0.5.7" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "istanbul-reports": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "handlebars": "4.0.11" + } + }, + "js-tokens": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "jsesc": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + }, + "lazy-cache": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "lodash": { + "version": "4.17.10", + "bundled": true, + "dev": true + }, + "longest": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "map-cache": { + "version": "0.2.2", + "bundled": true, + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "object-visit": "1.0.1" + } + }, + "md5-hex": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "md5-o-matic": "0.1.1" + } + }, + "md5-o-matic": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "mem": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "merge-source-map": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + } + } + }, + "micromatch": { + "version": "3.1.10", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "for-in": "1.0.2", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "nanomatch": { + "version": "1.2.9", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-odd": "2.0.0", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "2.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "requires": { + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "object.pick": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "1.2.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "pascalcase": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true, + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "find-up": "1.1.2" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + } + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "bundled": true, + "dev": true + }, + "regex-not": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" + } + }, + "repeat-element": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "bundled": true, + "dev": true + }, + "repeating": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "resolve-from": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "ret": { + "version": "0.1.15", + "bundled": true, + "dev": true + }, + "right-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-regex": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "ret": "0.1.15" + } + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "set-value": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "requires": { + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.1", + "use": "3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "source-map": { + "version": "0.5.7", + "bundled": true, + "dev": true + }, + "source-map-resolve": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "atob": "2.1.1", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "spawn-wrap": { + "version": "1.4.2", + "bundled": true, + "dev": true, + "requires": { + "foreground-child": "1.5.6", + "mkdirp": "0.5.1", + "os-homedir": "1.0.2", + "rimraf": "2.6.2", + "signal-exit": "3.0.2", + "which": "1.3.0" + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "split-string": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "3.0.2" + } + }, + "static-extend": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "requires": { + "define-property": "0.2.5", + "object-copy": "0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + } + } + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "test-exclude": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "requires": { + "arrify": "1.0.1", + "micromatch": "3.1.10", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "braces": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "requires": { + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.2", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "requires": { + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "bundled": true, + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + } + } + } + }, + "to-fast-properties": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "to-regex": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-number": "3.0.0", + "repeat-string": "1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + } + } + }, + "trim-right": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "union-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "set-value": { + "version": "0.4.3", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" + } + } + } + }, + "unset-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "has-value": "0.3.1", + "isobject": "3.0.1" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "bundled": true, + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "bundled": true, + "dev": true + }, + "use": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "which": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "window-size": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + }, + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "11.1.0", + "bundled": true, + "dev": true, + "requires": { + "cliui": "4.1.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "cliui": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "8.1.0", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + } + } + } + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "observable-to-promise": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/observable-to-promise/-/observable-to-promise-0.5.0.tgz", + "integrity": "sha1-yCjw8NxH6fhq+KSXfF1VB2znqR8=", + "dev": true, + "requires": { + "is-observable": "0.2.0", + "symbol-observable": "1.2.0" + }, + "dependencies": { + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + } + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "option-chain": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/option-chain/-/option-chain-1.0.0.tgz", + "integrity": "sha1-k41zvU4Xg/lI00AjZEraI2aeMPI=", + "dev": true + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.3.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "package-hash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-2.0.0.tgz", + "integrity": "sha1-eK4ybIngWk2BO2hgGXevBcANKg0=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "lodash.flattendeep": "4.4.0", + "md5-hex": "2.0.0", + "release-zalgo": "1.0.0" + } + }, + "package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, + "requires": { + "got": "6.7.1", + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0", + "semver": "5.5.0" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.2" + } + }, + "parse-ms": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", + "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz", + "integrity": "sha1-Wkfyi6EBXQIBvae/DzWOR77Ix+Q=", + "dev": true + }, + "pinkie-promise": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz", + "integrity": "sha1-0dpn9UglY7t89X8oauKCLs+/NnA=", + "dev": true, + "requires": { + "pinkie": "1.0.0" + } + }, + "pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "load-json-file": "4.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "4.0.0", + "pify": "3.0.0", + "strip-bom": "3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "1.3.2", + "json-parse-better-errors": "1.0.2" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "2.1.0" + } + }, + "pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "dev": true, + "requires": { + "find-up": "1.1.2" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + } + } + }, + "plur": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", + "integrity": "sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo=", + "dev": true, + "requires": { + "irregular-plurals": "1.4.0" + } + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", + "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=", + "dev": true, + "requires": { + "is-finite": "1.0.2", + "parse-ms": "1.0.1", + "plur": "1.0.0" + }, + "dependencies": { + "plur": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz", + "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=", + "dev": true + } + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "randomatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", + "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", + "dev": true, + "requires": { + "is-number": "4.0.0", + "kind-of": "6.0.2", + "math-random": "1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "0.6.0", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.6", + "set-immediate-shim": "1.0.1" + } + }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "mute-stream": "0.0.5" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "1.8.1" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + }, + "dependencies": { + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + } + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "1.4.0", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "dev": true, + "requires": { + "rc": "1.2.8", + "safe-buffer": "5.1.2" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "requires": { + "rc": "1.2.8" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "0.5.0" + } + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "4.1.1" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.1.2", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.3.0" + } + }, + "require-precompiled": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/require-precompiled/-/require-precompiled-0.1.0.tgz", + "integrity": "sha1-WhtS63Dr7UPrmC6XTIWrWVceVvo=", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + } + } + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true, + "requires": { + "once": "1.4.0" + } + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "5.5.0" + } + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz", + "integrity": "sha1-7GIRvtGSBEIIj+D3Cyg3Iy7SyKg=", + "dev": true + }, + "shelljs-changelog": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/shelljs-changelog/-/shelljs-changelog-0.2.5.tgz", + "integrity": "sha1-qDkhj9cqyfz4QGW8lNzTCzDS/x8=", + "dev": true, + "requires": { + "shelljs": "0.7.8" + }, + "dependencies": { + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.1.0", + "rechoir": "0.6.2" + } + } + } + }, + "shelljs-release": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs-release/-/shelljs-release-0.3.0.tgz", + "integrity": "sha512-mTFv773NZF83TyOhmbOT+u7dlh5uqCawvGBuaM6ArHhDo4Y+XNPkZ5m1U9eUfoAJg6Cfiag21JbLO+d13guDXw==", + "dev": true, + "requires": { + "minimist": "1.2.0", + "shelljs": "0.7.8" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.1.0", + "rechoir": "0.6.2" + } + } + } + }, + "shx": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.2.2.tgz", + "integrity": "sha1-CjBNAgsO3xMGrYFXDoDwNG31ijk=", + "dev": true, + "requires": { + "es6-object-assign": "1.1.0", + "minimist": "1.2.0", + "shelljs": "0.7.8" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.1.0", + "rechoir": "0.6.2" + } + } + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "1.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "dev": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" + } + }, + "stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-bom-buf": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz", + "integrity": "sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + }, + "symbol-observable": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-0.2.4.tgz", + "integrity": "sha1-lag9smGG1q9+ehjb2XYKL4bQj0A=", + "dev": true + }, + "table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.10", + "slice-ansi": "0.0.4", + "string-width": "2.1.1" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + } + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "0.7.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "2.3.6", + "xtend": "4.0.1" + } + }, + "time-require": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/time-require/-/time-require-0.1.2.tgz", + "integrity": "sha1-+eEss3D8JgXhFARYK6VO9corLZg=", + "dev": true, + "requires": { + "chalk": "0.4.0", + "date-time": "0.1.1", + "pretty-ms": "0.2.2", + "text-table": "0.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "1.0.0", + "has-color": "0.1.7", + "strip-ansi": "0.1.1" + } + }, + "date-time": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-0.1.1.tgz", + "integrity": "sha1-7S9tk9l5DOL9ZtW1/z7dW7y/Owc=", + "dev": true + }, + "parse-ms": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-0.1.2.tgz", + "integrity": "sha1-3T+iXtbC78e93hKtm0bBY6opIk4=", + "dev": true + }, + "pretty-ms": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-0.2.2.tgz", + "integrity": "sha1-2oeaaC/zOjcBEEbxPWJ/Z8c7hPY=", + "dev": true, + "requires": { + "parse-ms": "0.1.2" + } + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + } + } + }, + "time-zone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", + "integrity": "sha1-mcW/VZWJZq9tBtg73zgA3IL67F0=", + "dev": true + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "travis-check-changes": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/travis-check-changes/-/travis-check-changes-0.2.0.tgz", + "integrity": "sha1-60H3EgiBTgkryRR3O5SaNT0T+SI=", + "dev": true, + "requires": { + "shelljs": "0.7.8" + }, + "dependencies": { + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.1.0", + "rechoir": "0.6.2" + } + } + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "trim-off-newlines": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", + "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=", + "dev": true + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "1.0.0" + } + }, + "unique-temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-temp-dir/-/unique-temp-dir-1.0.0.tgz", + "integrity": "sha1-bc6VsmgcoAPuv7MEpBX5y6vMU4U=", + "dev": true, + "requires": { + "mkdirp": "0.5.1", + "os-tmpdir": "1.0.2", + "uid2": "0.0.3" + } + }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true + }, + "update-notifier": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", + "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "dev": true, + "requires": { + "boxen": "1.3.0", + "chalk": "2.4.1", + "configstore": "3.1.2", + "import-lazy": "2.1.0", + "is-ci": "1.1.0", + "is-installed-globally": "0.1.0", + "is-npm": "1.0.0", + "latest-version": "3.1.0", + "semver-diff": "2.1.0", + "xdg-basedir": "3.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "1.0.4" + } + }, + "urlgrey": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz", + "integrity": "sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8=", + "dev": true + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.0.tgz", + "integrity": "sha512-ijO9N2xY/YaOqQ5yz5c4sy2ZjWmA6AR6zASb/gdpeKZ8+948CxwfMW9RrKVk5may6ev8c0/Xguu32e2Llelpqw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", + "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "dev": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "well-known-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-1.0.0.tgz", + "integrity": "sha1-c8eK6Bp3Jqj6WY4ogIAcixYiVRg=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "widest-line": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.0.tgz", + "integrity": "sha1-AUKk6KJD+IgsAjOqDgKBqnYVInM=", + "dev": true, + "requires": { + "string-width": "2.1.1" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "write-file-atomic": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", + "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "signal-exit": "3.0.2" + } + }, + "write-json-file": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-2.3.0.tgz", + "integrity": "sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8=", + "dev": true, + "requires": { + "detect-indent": "5.0.0", + "graceful-fs": "4.1.11", + "make-dir": "1.3.0", + "pify": "3.0.0", + "sort-keys": "2.0.0", + "write-file-atomic": "2.3.0" + }, + "dependencies": { + "detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "write-pkg": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-3.2.0.tgz", + "integrity": "sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw==", + "dev": true, + "requires": { + "sort-keys": "2.0.0", + "write-json-file": "2.3.0" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } +} diff --git a/package.json b/package.json index 9fd41b6e2..fd9e02d00 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "devDependencies": { "ava": "^0.21.0", "chalk": "^1.1.3", - "codecov": "^1.0.1", + "codecov": "^3.0.2", "coffee-script": "^1.10.0", "eslint": "^2.0.0", "eslint-config-airbnb-base": "^3.0.0", From 1dd437eb6b29a2d9e88ed1542cba5a3bd4e66c99 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 28 Jun 2018 14:15:54 -0700 Subject: [PATCH 54/71] fix(mocks): fix conflict between mocks and skip (#863) This fixes a conflict between mocks.init() and utils.skipOnWin/skipOnUnix. mocks.init() mocks out process.stderr.write, which utils.js implicitly depends on. Instead, preserve stderr.write in a local variable to avoid polluting mocked stdio and to correctly output warning messages. Fixes #862 Test: locally apply mocks.init() inside test/which.js --- test/utils/utils.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/utils/utils.js b/test/utils/utils.js index aae5cdefb..1a3020c1d 100644 --- a/test/utils/utils.js +++ b/test/utils/utils.js @@ -5,6 +5,9 @@ const chalk = require('chalk'); const common = require('../../src/common'); +// Capture process.stderr.write, otherwise we have a conflict with mocks.js +const _processStderrWrite = process.stderr.write.bind(process.stderr); + function numLines(str) { return typeof str === 'string' ? (str.match(/\n/g) || []).length + 1 : 0; } @@ -23,7 +26,7 @@ function skipOnWinForEPERM(action, testCase) { const error = ret.code; const isWindows = process.platform === 'win32'; if (isWindows && error && /EPERM:/.test(error)) { - console.warn('Got EPERM when testing symlinks on Windows. Assuming non-admin environment and skipping test.'); + _processStderrWrite('Got EPERM when testing symlinks on Windows. Assuming non-admin environment and skipping test.\n'); } else { testCase(); } @@ -56,9 +59,10 @@ exports.mkfifo = mkfifo; function skipIfTrue(booleanValue, t, closure) { if (booleanValue) { - console.warn( + _processStderrWrite( chalk.yellow('Warning: skipping platform-dependent test ') + - chalk.bold.white(`'${t._test.title}'`) + chalk.bold.white(`'${t._test.title}'`) + + '\n' ); t.truthy(true); // dummy assertion to satisfy ava v0.19+ } else { From 131b88f992346085ed436e02e02e78935f379ae6 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 9 Jul 2018 22:53:58 -0700 Subject: [PATCH 55/71] Fix cp from readonly source (#870) This is a redo of PR #555. This rebases, cleans up a test, and fixes a bug (the original PR uses `fs.chown()` instead of `fs.chownSync()`). Fixes #98 --- src/cp.js | 8 ++++++-- test/cp.js | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/cp.js b/src/cp.js index 4214b0bdf..6218f6700 100644 --- a/src/cp.js +++ b/src/cp.js @@ -99,8 +99,7 @@ function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { // Create the directory where all our junk is moving to; read the mode of the // source directory and mirror it try { - var checkDir = common.statFollowLinks(sourceDir); - fs.mkdirSync(destDir, checkDir.mode); + fs.mkdirSync(destDir); } catch (e) { // if the directory already exists, that's okay if (e.code !== 'EEXIST') throw e; @@ -151,6 +150,11 @@ function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { } } } // for files + + // finally change the mode for the newly created directory (otherwise, we + // couldn't add files to a read-only directory). + var checkDir = common.statFollowLinks(sourceDir); + fs.chmodSync(destDir, checkDir.mode); } // cpdirSyncRecursive // Checks if cureent file was created recently diff --git a/test/cp.js b/test/cp.js index 8ada327ad..7007917d7 100644 --- a/test/cp.js +++ b/test/cp.js @@ -756,3 +756,27 @@ test('should not overwrite recently created files (not give error no-force mode) // Ensure First file is copied t.is(shell.cat(`${t.context.tmp}/file1`).toString(), 'test1'); }); + +// cp -R should be able to copy a readonly src (issue #98). +// On Windows, chmod acts VERY differently so skip these tests for now +test('cp -R should be able to copy a readonly src. issue #98; (Non window platforms only)', t => { + utils.skipOnWin(t, () => { + shell.cp('-r', 'test/resources/cp', t.context.tmp); + shell.chmod('555', `${t.context.tmp}/cp/`); + shell.chmod('555', `${t.context.tmp}/cp/dir_a`); + shell.chmod('555', `${t.context.tmp}/cp/dir_b`); + shell.chmod('555', `${t.context.tmp}/cp/a`); + + const result = shell.cp('-r', `${t.context.tmp}/cp`, `${t.context.tmp}/cp_cp`); + t.falsy(shell.error()); + t.falsy(result.stderr); + t.is(result.code, 0); + + t.is(shell.ls('-R', `${t.context.tmp}/cp`) + '', shell.ls('-R', `${t.context.tmp}/cp_cp`) + ''); + t.is(fs.statSync(`${t.context.tmp}/cp_cp`).mode & parseInt('777', 8), parseInt('555', 8)); + t.is(fs.statSync(`${t.context.tmp}/cp_cp/dir_a`).mode & parseInt('777', 8), parseInt('555', 8)); + t.is(fs.statSync(`${t.context.tmp}/cp_cp/a`).mode & parseInt('777', 8), parseInt('555', 8)); + + shell.chmod('-R', '755', t.context.tmp); + }); +}); From 6d66a1af98430bc0275e2125d4cae41ccb0de645 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Wed, 11 Jul 2018 15:06:20 -0700 Subject: [PATCH 56/71] chore: rename some tests (#871) No change to logic. This renames some tests to be a bit more readable. --- test/cp.js | 129 +++++++++++++++++++++++---------------------------- test/echo.js | 6 +-- 2 files changed, 61 insertions(+), 74 deletions(-) diff --git a/test/cp.js b/test/cp.js index 7007917d7..660dcb881 100644 --- a/test/cp.js +++ b/test/cp.js @@ -54,7 +54,7 @@ test('invalid option', t => { t.is(result.stderr, 'cp: option not recognized: @'); }); -test('invalid option', t => { +test('invalid option #2', t => { const result = shell.cp('-Z', 'asdfasdf', `${t.context.tmp}/file2`); t.truthy(shell.error()); t.is(result.code, 1); @@ -265,39 +265,34 @@ test('recursive, nothing exists', t => { t.is(shell.ls('-R', 'test/resources/cp').toString(), shell.ls('-R', `${t.context.tmp}/cp`).toString()); }); -test( - 'recursive, nothing exists, source ends in \'/\' (see Github issue #15)', - t => { - const result = shell.cp('-R', 'test/resources/cp/', `${t.context.tmp}/`); - t.falsy(shell.error()); - t.falsy(result.stderr); - t.is(result.code, 0); - t.is(shell.ls('-R', 'test/resources/cp').toString(), shell.ls('-R', `${t.context.tmp}/cp`).toString()); - } -); +test('recursive, nothing exists, source ends in "/"', t => { + // Github issue #15 + const result = shell.cp('-R', 'test/resources/cp/', `${t.context.tmp}/`); + t.falsy(shell.error()); + t.falsy(result.stderr); + t.is(result.code, 0); + t.is(shell.ls('-R', 'test/resources/cp').toString(), shell.ls('-R', `${t.context.tmp}/cp`).toString()); +}); -test( - 'recursive, globbing regular files with extension (see Github issue #376)', - t => { - const result = shell.cp('-R', 'test/resources/file*.txt', t.context.tmp); - t.falsy(shell.error()); - t.falsy(result.stderr); - t.is(result.code, 0); - t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`)); - t.truthy(fs.existsSync(`${t.context.tmp}/file2.txt`)); - } -); +test('recursive, globbing regular files with extension', t => { + // Github issue #376 + const result = shell.cp('-R', 'test/resources/file*.txt', t.context.tmp); + t.falsy(shell.error()); + t.falsy(result.stderr); + t.is(result.code, 0); + t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`)); + t.truthy(fs.existsSync(`${t.context.tmp}/file2.txt`)); +}); -test( - 'recursive, copying one regular file (also related to Github issue #376)', - t => { - const result = shell.cp('-R', 'test/resources/file1.txt', t.context.tmp); - t.falsy(shell.error()); - t.falsy(result.stderr); - t.is(result.code, 0); - t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`)); - t.falsy(common.statFollowLinks(`${t.context.tmp}/file1.txt`).isDirectory()); // don't let it be a dir - } +test('recursive, copying one regular file', t => { + // Github issue #376 + const result = shell.cp('-R', 'test/resources/file1.txt', t.context.tmp); + t.falsy(shell.error()); + t.falsy(result.stderr); + t.is(result.code, 0); + t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`)); + t.falsy(common.statFollowLinks(`${t.context.tmp}/file1.txt`).isDirectory()); // don't let it be a dir +} ); test('recursive, everything exists, no force flag', t => { @@ -365,34 +360,30 @@ test('recursive, everything exists, with force flag', t => { t.is(shell.cat('test/resources/cp/dir_a/z').toString(), shell.cat(`${t.context.tmp}/cp/dir_a/z`).toString()); // after cp }); -test( - 'recursive, creates dest dir since it\'s only one level deep (see Github issue #44)', - t => { - const result = shell.cp('-r', 'test/resources/issue44', `${t.context.tmp}/dir2`); - t.falsy(shell.error()); - t.falsy(result.stderr); - t.is(result.code, 0); - t.is(shell.ls('-R', 'test/resources/issue44').toString(), shell.ls('-R', `${t.context.tmp}/dir2`).toString()); - t.is( +test("recursive, creates dest dir since it's only one level deep", t => { + // Github issue #44 + const result = shell.cp('-r', 'test/resources/issue44', `${t.context.tmp}/dir2`); + t.falsy(shell.error()); + t.falsy(result.stderr); + t.is(result.code, 0); + t.is(shell.ls('-R', 'test/resources/issue44').toString(), shell.ls('-R', `${t.context.tmp}/dir2`).toString()); + t.is( shell.cat('test/resources/issue44/main.js').toString(), shell.cat(`${t.context.tmp}/dir2/main.js`).toString() ); - } -); +}); -test( - 'recursive, does *not* create dest dir since it\'s too deep (see Github issue #44)', - t => { - const result = shell.cp('-r', 'test/resources/issue44', `${t.context.tmp}/dir2/dir3`); - t.truthy(shell.error()); - t.is( - result.stderr, - `cp: cannot create directory '${t.context.tmp}/dir2/dir3': No such file or directory` - ); - t.is(result.code, 1); - t.falsy(fs.existsSync(`${t.context.tmp}/dir2`)); - } -); +test("recursive, does *not* create dest dir since it's too deep", t => { + // Github issue #44 + const result = shell.cp('-r', 'test/resources/issue44', `${t.context.tmp}/dir2/dir3`); + t.truthy(shell.error()); + t.is( + result.stderr, + `cp: cannot create directory '${t.context.tmp}/dir2/dir3': No such file or directory` + ); + t.is(result.code, 1); + t.falsy(fs.existsSync(`${t.context.tmp}/dir2`)); +}); test('recursive, copies entire directory', t => { const result = shell.cp('-r', 'test/resources/cp/dir_a', `${t.context.tmp}/dest`); @@ -409,21 +400,17 @@ test('recursive, with trailing slash, does the exact same', t => { t.truthy(fs.existsSync(`${t.context.tmp}/dest/z`)); }); -test( - 'On Windows, permission bits are quite different so skip those tests for now', - t => { - utils.skipOnWin(t, () => { - // preserve mode bits - const execBit = parseInt('001', 8); - t.is(common.statFollowLinks('test/resources/cp-mode-bits/executable').mode & execBit, execBit); - shell.cp('test/resources/cp-mode-bits/executable', `${t.context.tmp}/executable`); - t.is( - common.statFollowLinks('test/resources/cp-mode-bits/executable').mode, - common.statFollowLinks(`${t.context.tmp}/executable`).mode - ); - }); - } -); +test('preserve mode bits by default for file', t => { + utils.skipOnWin(t, () => { + const execBit = parseInt('001', 8); + t.is(common.statFollowLinks('test/resources/cp-mode-bits/executable').mode & execBit, execBit); + shell.cp('test/resources/cp-mode-bits/executable', `${t.context.tmp}/executable`); + t.is( + common.statFollowLinks('test/resources/cp-mode-bits/executable').mode, + common.statFollowLinks(`${t.context.tmp}/executable`).mode + ); + }); +}); test('Make sure hidden files are copied recursively', t => { shell.rm('-rf', t.context.tmp); diff --git a/test/echo.js b/test/echo.js index f8afbee26..1d571e49b 100644 --- a/test/echo.js +++ b/test/echo.js @@ -31,7 +31,7 @@ test('simple test with defaults', t => { }); test('allow arguments to begin with a hyphen', t => { - // see issue #20 + // Github issue #20 const result = shell.echo('-asdf', '111'); const stdout = mocks.stdout(); const stderr = mocks.stderr(); @@ -62,7 +62,7 @@ test('-e option', t => { }); test('piping to a file', t => { - // see issue #476 + // Github issue #476 shell.mkdir(t.context.tmp); const tmp = `${t.context.tmp}/echo.txt`; const resultA = shell.echo('A').toEnd(tmp); @@ -121,7 +121,7 @@ test('-en option with escaped characters', t => { }); test('piping to a file with -n', t => { - // see issue #476 + // Github issue #476 shell.mkdir(t.context.tmp); const tmp = `${t.context.tmp}/echo.txt`; const resultA = shell.echo('-n', 'A').toEnd(tmp); From 8dae55ff4ac89017eb2fd071b94e8464b1a20bdc Mon Sep 17 00:00:00 2001 From: Stanislav Termosa Date: Thu, 19 Jul 2018 01:33:08 +0300 Subject: [PATCH 57/71] Fix(which): match only executable files (#874) On Unix, this only matches files with the exec bit set. On Windows, this only matches files which are readable (since Windows has different rules for execution). Fixes #657. --- src/which.js | 27 +++++++++++++++++++++++---- test/resources/which/node | 1 + test/which.js | 25 ++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 test/resources/which/node diff --git a/src/which.js b/src/which.js index 0e5433c03..cc497384e 100644 --- a/src/which.js +++ b/src/which.js @@ -13,13 +13,33 @@ common.register('which', _which, { // set on Windows. var XP_DEFAULT_PATHEXT = '.com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh'; +// For earlier versions of NodeJS that doesn't have a list of constants (< v6) +var FILE_EXECUTABLE_MODE = 1; + +function isWindowsPlatform() { + return process.platform === 'win32'; +} + // Cross-platform method for splitting environment `PATH` variables function splitPath(p) { return p ? p.split(path.delimiter) : []; } +// Tests are running all cases for this func but it stays uncovered by codecov due to unknown reason +/* istanbul ignore next */ +function isExecutable(pathName) { + try { + // TODO(node-support): replace with fs.constants.X_OK once remove support for node < v6 + fs.accessSync(pathName, FILE_EXECUTABLE_MODE); + } catch (err) { + return false; + } + return true; +} + function checkPath(pathName) { - return fs.existsSync(pathName) && !common.statFollowLinks(pathName).isDirectory(); + return fs.existsSync(pathName) && !common.statFollowLinks(pathName).isDirectory() + && (isWindowsPlatform() || isExecutable(pathName)); } //@ @@ -37,9 +57,8 @@ function checkPath(pathName) { function _which(options, cmd) { if (!cmd) common.error('must specify command'); - var isWindows = process.platform === 'win32'; - var pathEnv = process.env.path || process.env.Path || process.env.PATH; - var pathArray = splitPath(pathEnv); + var isWindows = isWindowsPlatform(); + var pathArray = splitPath(process.env.PATH); var queryMatches = []; diff --git a/test/resources/which/node b/test/resources/which/node new file mode 100644 index 000000000..0b917ba31 --- /dev/null +++ b/test/resources/which/node @@ -0,0 +1 @@ +text file, not an executable diff --git a/test/which.js b/test/which.js index 530fcd2ca..f81d9e0e2 100644 --- a/test/which.js +++ b/test/which.js @@ -1,4 +1,5 @@ import fs from 'fs'; +import path from 'path'; import test from 'ava'; @@ -69,5 +70,27 @@ test('Searching with -a flag returns an array with first item equals to the regu t.falsy(shell.error()); t.truthy(resultForWhich); t.truthy(resultForWhichA); - t.is(resultForWhich.toString(), resultForWhichA[0].toString()); + t.is(resultForWhich.toString(), resultForWhichA[0]); +}); + +test('None executable files does not appear in the result list', t => { + const commandName = 'node'; // Should be an existing command + const extraPath = path.resolve(__dirname, 'resources', 'which'); + const matchingFile = path.resolve(extraPath, commandName); + const pathEnv = process.env.PATH; + + // make sure that file is exists (will throw error otherwise) + t.truthy(fs.existsSync(matchingFile)); + + process.env.PATH = extraPath + path.delimiter + process.env.PATH; + const resultForWhich = shell.which(commandName); + const resultForWhichA = shell.which('-a', commandName); + t.falsy(shell.error()); + t.truthy(resultForWhich); + t.truthy(resultForWhichA); + t.truthy(resultForWhichA.length); + t.not(resultForWhich.toString(), matchingFile); + t.is(resultForWhichA.indexOf(matchingFile), -1); + + process.env.PATH = pathEnv; }); From 4113a72c16dc919ca0f204c9552eaf9247a9dc37 Mon Sep 17 00:00:00 2001 From: Peng Zhao Date: Mon, 23 Jul 2018 11:38:13 +0800 Subject: [PATCH 58/71] grep includes the i flag (#876) grep includes the i flag to ignored upper/lower case differences --- README.md | 3 ++- src/grep.js | 7 ++++++- test/grep.js | 7 +++++++ test/resources/grep/case1 | 1 + test/resources/grep/case1.js | 1 + test/resources/grep/case1.txt | 1 + 6 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 test/resources/grep/case1 create mode 100644 test/resources/grep/case1.js create mode 100644 test/resources/grep/case1.txt diff --git a/README.md b/README.md index cf916b94c..43ce1411b 100644 --- a/README.md +++ b/README.md @@ -362,7 +362,8 @@ include the base directories (e.g., `lib/resources/file1` instead of just `file1 Available options: + `-v`: Invert `regex_filter` (only print non-matching lines). -+ `-l`: Print only filenames of matching files ++ `-l`: Print only filenames of matching files. ++ `-i`: Ignore case. Examples: diff --git a/src/grep.js b/src/grep.js index 3880fa191..b696792a7 100644 --- a/src/grep.js +++ b/src/grep.js @@ -7,6 +7,7 @@ common.register('grep', _grep, { cmdOptions: { 'v': 'inverse', 'l': 'nameOnly', + 'i': 'ignoreCase', }, }); @@ -17,7 +18,8 @@ common.register('grep', _grep, { //@ Available options: //@ //@ + `-v`: Invert `regex_filter` (only print non-matching lines). -//@ + `-l`: Print only filenames of matching files +//@ + `-l`: Print only filenames of matching files. +//@ + `-i`: Ignore case. //@ //@ Examples: //@ @@ -41,6 +43,9 @@ function _grep(options, regex, files) { } var grep = []; + if (options.ignoreCase) { + regex = new RegExp(regex, 'i'); + } files.forEach(function (file) { if (!fs.existsSync(file) && file !== '-') { common.error('no such file or directory: ' + file, 2, { continue: true }); diff --git a/test/grep.js b/test/grep.js index f450aabb1..f973640cc 100644 --- a/test/grep.js +++ b/test/grep.js @@ -137,6 +137,13 @@ test('-l option', t => { t.is(result.split('\n').length - 1, 2); }); +test('-i option', t => { + const result = shell.grep('-i', 'test', 'test/resources/grep/case1', 'test/resources/grep/case1.txt', + 'test/resources/grep/case1.js'); + t.falsy(shell.error()); + t.is(result.split('\n').length - 1, 3); +}); + test('the pattern looks like an option', t => { const result = shell.grep('--', '-v', 'test/resources/grep/file2'); t.falsy(shell.error()); diff --git a/test/resources/grep/case1 b/test/resources/grep/case1 new file mode 100644 index 000000000..b08f7b082 --- /dev/null +++ b/test/resources/grep/case1 @@ -0,0 +1 @@ +Test3 diff --git a/test/resources/grep/case1.js b/test/resources/grep/case1.js new file mode 100644 index 000000000..df6b0d2bc --- /dev/null +++ b/test/resources/grep/case1.js @@ -0,0 +1 @@ +test3 diff --git a/test/resources/grep/case1.txt b/test/resources/grep/case1.txt new file mode 100644 index 000000000..bac87cc8e --- /dev/null +++ b/test/resources/grep/case1.txt @@ -0,0 +1 @@ +TEST3 From d0795156537f83f353deb4834d6cd2c31e212ef9 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 9 Oct 2018 19:28:20 -0700 Subject: [PATCH 59/71] docs: remove gitter badge (#880) No change to logic. We don't really use the gitter chatroom right now, so we shouldn't direct users to chat there. It's best to have issues reported directly on Github. This PR removes the gitter badge from the README. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 43ce1411b..bead36e93 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # ShellJS - Unix shell commands for Node.js -[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square)](https://gitter.im/shelljs/shelljs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Travis](https://img.shields.io/travis/shelljs/shelljs/master.svg?style=flat-square&label=unix)](https://travis-ci.org/shelljs/shelljs) [![AppVeyor](https://img.shields.io/appveyor/ci/shelljs/shelljs/master.svg?style=flat-square&label=windows)](https://ci.appveyor.com/project/shelljs/shelljs/branch/master) [![Codecov](https://img.shields.io/codecov/c/github/shelljs/shelljs/master.svg?style=flat-square&label=coverage)](https://codecov.io/gh/shelljs/shelljs) From 4e861db8f9082e946a62b042753b1c227755c80c Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 9 Oct 2018 19:28:43 -0700 Subject: [PATCH 60/71] chore(appveyor): run entire test matrix (#886) No change to logic. This changes appveyor to run the entire test matrix, even if a failure occurs early on. This is helpful for debugging. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index f66b81748..24e22b33c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,7 +18,7 @@ install: - npm install matrix: - fast_finish: true + fast_finish: false # No need for MSBuild on this project build: off From 37acb86e89ea03ef8ab6ec9b24f5d1dcd93e8f3f Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 27 Oct 2018 13:48:31 -0700 Subject: [PATCH 61/71] chore(npm): add ci-or-install script (#896) * chore(npm): add ci-or-install script This adds a script which checks the npm version and runs either `npm ci` or `npm install` based on support. This is primarily to work around an issue where `npm install` modifies `package-lock.json` for newer npm versions. A side benefit is that `npm ci` is slightly faster than `npm install`. Fixes #893 --- .travis.yml | 2 +- appveyor.yml | 2 +- package-lock.json | 537 +++++++++++++++++++++++++++++++++++++++ package.json | 1 + scripts/ci-or-install.js | 41 +++ 5 files changed, 581 insertions(+), 2 deletions(-) create mode 100755 scripts/ci-or-install.js diff --git a/.travis.yml b/.travis.yml index bb164d863..fd60d6d94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ install: - nvm install $NODE_VERSION - node --version - npm --version - - npm install + - npm run ci-or-install os: - linux - osx diff --git a/appveyor.yml b/appveyor.yml index 24e22b33c..ca4d4cbd5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,7 +15,7 @@ install: - set PATH=%APPDATA%\npm;%PATH% - node --version - npm --version - - npm install + - npm run ci-or-install matrix: fast_finish: false diff --git a/package-lock.json b/package-lock.json index f2ebfb5cd..4a3d67b5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1057,6 +1057,7 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", + "fsevents": "1.2.4", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -2034,6 +2035,535 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", + "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.11.1", + "node-pre-gyp": "0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "2.2.4" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.21", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.1.1", + "yallist": "3.0.2" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "2.2.4" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.9", + "iconv-lite": "0.4.21", + "sax": "1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "1.0.3", + "mkdirp": "0.5.1", + "needle": "2.2.0", + "nopt": "4.0.1", + "npm-packlist": "1.1.10", + "npmlog": "4.1.2", + "rc": "1.2.7", + "rimraf": "2.6.2", + "semver": "5.5.0", + "tar": "4.4.1" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.1", + "osenv": "0.1.5" + } + }, + "npm-bundled": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.1.10", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "3.0.1", + "npm-bundled": "1.0.3" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.5.1", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "1.0.1", + "fs-minipass": "1.2.5", + "minipass": "2.2.4", + "minizlib": "1.1.0", + "mkdirp": "0.5.1", + "safe-buffer": "5.1.1", + "yallist": "3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true, + "dev": true + } + } + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3274,6 +3804,13 @@ "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", "dev": true }, + "nan": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", + "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", + "dev": true, + "optional": true + }, "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", diff --git a/package.json b/package.json index fd9e02d00..c4e8a551e 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "src" ], "scripts": { + "ci-or-install": "node scripts/ci-or-install", "posttest": "npm run lint", "test": "nyc --reporter=text --reporter=lcov ava test/*.js", "test-no-coverage": "ava test/*.js", diff --git a/scripts/ci-or-install.js b/scripts/ci-or-install.js new file mode 100755 index 000000000..e71cd1e33 --- /dev/null +++ b/scripts/ci-or-install.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node +var childProcess = require('child_process'); +// Note: can't use 3P modules or shelljs, because this must run before we +// download dependencies. + +// Also, we must use exec{Sync} because `npm` is a batch script on Windows, +// which must run in-process in the shell, and the 'shell' option isn't +// supported on node v4. + +function Version(components) { + this.components = components; +} + +Version.prototype.isAtLeast = function (other) { + if (this.components.length !== 3 || other.components.length !== 3) { + throw new Error('version numbers must have 3 components.'); + } + for (var k = 0; k < this.components.length; k++) { + if (this.components[k] > other.components[k]) return true; + if (this.components[k] < other.components[k]) return false; + } + // At this point, the components must be equal. + return true; +}; + +var npmVersionComponents = childProcess.execSync('npm --version') + .toString().trim().split('.').map(function (str) { + return parseInt(str, 10); + }); +var npmVersion = new Version(npmVersionComponents); +var minimumVersionWithNpmCi = new Version([5, 7, 0]); + +var subcommand = npmVersion.isAtLeast(minimumVersionWithNpmCi) ? + 'ci' : + 'install'; + +console.log('Executing `npm ' + subcommand + '`'); +// Async. Node waits until this is finished. +var c = childProcess.exec('npm ' + subcommand); +c.stdout.pipe(process.stdout); +c.stderr.pipe(process.stderr); From 2b3b781bbc41add8ca17bcd35a6d8f19797285ce Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 27 Oct 2018 13:51:36 -0700 Subject: [PATCH 62/71] fix: silent exec (#892) Unconditionally apply `silent: true` when calling `common.error()` from `exec()`. This is because errors are already printed to stderr, or are intentionally silenced by `shell.config.silent`. Based on #861 Fixes #851 --- src/exec.js | 5 ++++- test/exec.js | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/exec.js b/src/exec.js index 66ef3d736..a73e2cd40 100644 --- a/src/exec.js +++ b/src/exec.js @@ -96,7 +96,10 @@ function execSync(cmd, opts, pipe) { try { common.unlinkSync(stdoutFile); } catch (e) {} if (code !== 0) { - common.error(stderr, code, { continue: true }); + // Note: `silent` should be unconditionally true to avoid double-printing + // the command's stderr, and to avoid printing any stderr when the user has + // set `shell.config.silent`. + common.error(stderr, code, { continue: true, silent: true }); } var obj = common.ShellString(stdout, stderr, code); return obj; diff --git a/test/exec.js b/test/exec.js index 2cd2a67fd..18c9b1b53 100644 --- a/test/exec.js +++ b/test/exec.js @@ -6,14 +6,20 @@ import test from 'ava'; import shell from '..'; import utils from './utils/utils'; +import mocks from './utils/mocks'; const CWD = process.cwd(); const ORIG_EXEC_PATH = shell.config.execPath; shell.config.silent = true; +test.beforeEach(() => { + mocks.init(); +}); + test.afterEach.always(() => { process.chdir(CWD); shell.config.execPath = ORIG_EXEC_PATH; + mocks.restore(); }); // @@ -85,6 +91,14 @@ test('check if stdout + stderr go to output', t => { t.is(result.stderr, '1234\n'); }); +test('check if stdout + stderr should not be printed to console if silent', t => { + shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.error(1234); console.log(666); process.exit(12);"`, { silent: true }); + const stdout = mocks.stdout(); + const stderr = mocks.stderr(); + t.is(stdout, ''); + t.is(stderr, ''); +}); + test('check exit code', t => { const result = shell.exec(`${JSON.stringify(shell.config.execPath)} -e "process.exit(12);"`); t.truthy(shell.error()); From 4bd22e77423182219cd43f0c8d38621b1c957986 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 6 Nov 2018 01:47:25 -0800 Subject: [PATCH 63/71] chore(ci): fix codecov on travis (#897) Apparently, travis hasn't been uploading any coverage data this whole time. This fixes the command (copied from appveyor). --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd60d6d94..de2e73551 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ script: - npm run gendocs - npm run after-travis "Make sure to generate docs!" after_success: - - codecov + - npm run codecov -- -f coverage/lcov.info # Gitter notifications: From 6b3c7b1e44b5cd308aac3a924165658fac3268d8 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 8 Nov 2018 23:00:22 -0800 Subject: [PATCH 64/71] refactor: don't expose tempdir in common.state (#903) Previously, the cached `tempdir` value was stored in `common.state`. Unlike the other `common.state` values, this isn't immediately useful to other commands (they can just call the tempdir API). So, this moves the cached value into `tempdir.js`. This also adds a unit test for the caching behavior, and exposes test-only helpers to verify this behavior. Finally, this adds a note to `common.state` that values should generally be considered read-only, since this can be important for customized behavior. Although, I recognize our code base has one exception to this rule (`echo()`), we should strive to maintain this. Fixes #902 Test: Added a unit test. --- src/common.js | 2 +- src/exec.js | 2 +- src/tempdir.js | 26 +++++++++++++++++++++----- test/tempdir.js | 10 ++++++++++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/common.js b/src/common.js index f873782bc..14a49fc58 100644 --- a/src/common.js +++ b/src/common.js @@ -42,11 +42,11 @@ var config = { config.reset(); exports.config = config; +// Note: commands should generally consider these as read-only values. var state = { error: null, errorCode: 0, currentCmd: 'shell.js', - tempDir: null, }; exports.state = state; diff --git a/src/exec.js b/src/exec.js index a73e2cd40..de3322c81 100644 --- a/src/exec.js +++ b/src/exec.js @@ -1,5 +1,5 @@ var common = require('./common'); -var _tempDir = require('./tempdir'); +var _tempDir = require('./tempdir').tempDir; var _pwd = require('./pwd'); var path = require('path'); var fs = require('fs'); diff --git a/src/tempdir.js b/src/tempdir.js index 6fe116fe2..b62032d7d 100644 --- a/src/tempdir.js +++ b/src/tempdir.js @@ -24,6 +24,8 @@ function writeableDir(dir) { } } +// Variable to cache the tempdir value for successive lookups. +var cachedTempDir; //@ //@ ### tempdir() @@ -37,10 +39,9 @@ function writeableDir(dir) { //@ Searches and returns string containing a writeable, platform-dependent temporary directory. //@ Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir). function _tempDir() { - var state = common.state; - if (state.tempDir) return state.tempDir; // from cache + if (cachedTempDir) return cachedTempDir; - state.tempDir = writeableDir(os.tmpdir()) || + cachedTempDir = writeableDir(os.tmpdir()) || writeableDir(process.env.TMPDIR) || writeableDir(process.env.TEMP) || writeableDir(process.env.TMP) || @@ -54,6 +55,21 @@ function _tempDir() { writeableDir('/usr/tmp') || writeableDir('.'); // last resort - return state.tempDir; + return cachedTempDir; } -module.exports = _tempDir; + +// Indicates if the tempdir value is currently cached. This is exposed for tests +// only. The return value should only be tested for truthiness. +function isCached() { + return cachedTempDir; +} + +// Clears the cached tempDir value, if one is cached. This is exposed for tests +// only. +function clearCache() { + cachedTempDir = undefined; +} + +module.exports.tempDir = _tempDir; +module.exports.isCached = isCached; +module.exports.clearCache = clearCache; diff --git a/test/tempdir.js b/test/tempdir.js index ed7ec77fd..c9c24754f 100644 --- a/test/tempdir.js +++ b/test/tempdir.js @@ -3,6 +3,7 @@ import fs from 'fs'; import test from 'ava'; import shell from '..'; +import { isCached, clearCache } from '../src/tempdir'; shell.config.silent = true; @@ -19,3 +20,12 @@ test('basic usage', t => { // It's a directory t.truthy(shell.test('-d', tmp)); }); + +test('cache', t => { + clearCache(); // In case this runs after any test which relies on tempdir(). + t.falsy(isCached()); + const tmp1 = shell.tempdir(); + t.truthy(isCached()); + const tmp2 = shell.tempdir(); + t.is(tmp1, tmp2); +}); From 0d5ecb673e65d4041a2ca26956deee7f5b9480f4 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 12 Nov 2018 20:27:35 -0800 Subject: [PATCH 65/71] docs(changelog): updated by Nate Fischer [ci skip] --- CHANGELOG.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15741bc80..68c9ccfb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,56 @@ # Change Log +## [Unreleased](https://github.com/shelljs/shelljs/tree/HEAD) + +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.8.2...HEAD) + +**Closed issues:** + +- Shelljs print stderr to console even if exec-only "silent" is true [\#905](https://github.com/shelljs/shelljs/issues/905) +- refactor: remove common.state.tempDir [\#902](https://github.com/shelljs/shelljs/issues/902) +- Can't suppress stdout for echo [\#899](https://github.com/shelljs/shelljs/issues/899) +- exec\(\) doesn't apply the arguments correctly [\#895](https://github.com/shelljs/shelljs/issues/895) +- Travis CI currently broken [\#893](https://github.com/shelljs/shelljs/issues/893) +- shell.exec\('npm pack'\) painfully slow [\#885](https://github.com/shelljs/shelljs/issues/885) +- shelljs.exec cannot find app.asar/node\_modules/shelljs/src/exec-child.js [\#881](https://github.com/shelljs/shelljs/issues/881) +- test infra: mocks and skipOnWin conflict [\#862](https://github.com/shelljs/shelljs/issues/862) +- Support for shell function completion on IDE [\#859](https://github.com/shelljs/shelljs/issues/859) +- echo command shows options in stdout [\#855](https://github.com/shelljs/shelljs/issues/855) +- silent does not always work [\#851](https://github.com/shelljs/shelljs/issues/851) +- Appveyor installs the latest npm, instead of the latest compatible npm [\#844](https://github.com/shelljs/shelljs/issues/844) +- Force symbolic link \(ln -sf\) does not overwrite/recreate existing destination [\#830](https://github.com/shelljs/shelljs/issues/830) +- inconsistent result when trying to echo to a file [\#798](https://github.com/shelljs/shelljs/issues/798) +- Prevent require\(\)ing executable-only files [\#789](https://github.com/shelljs/shelljs/issues/789) +- Cannot set property to of \[object String\] which has only a getter [\#752](https://github.com/shelljs/shelljs/issues/752) +- which\(\) should check executability before returning a value [\#657](https://github.com/shelljs/shelljs/issues/657) +- Bad encoding experience [\#456](https://github.com/shelljs/shelljs/issues/456) +- phpcs very slow [\#440](https://github.com/shelljs/shelljs/issues/440) +- Error shown when triggering a sigint during shelljs.exec if process.on sigint is defined [\#254](https://github.com/shelljs/shelljs/issues/254) +- `.to\(file\)` does not mute STDIO output [\#146](https://github.com/shelljs/shelljs/issues/146) +- Escaping shell arguments to exec\(\) [\#143](https://github.com/shelljs/shelljs/issues/143) +- Allow multiple string arguments for exec\(\) [\#103](https://github.com/shelljs/shelljs/issues/103) +- cp does not recursively copy from readonly location [\#98](https://github.com/shelljs/shelljs/issues/98) +- Handling permissions errors on file I/O [\#64](https://github.com/shelljs/shelljs/issues/64) + +**Merged pull requests:** + +- refactor: don't expose tempdir in common.state [\#903](https://github.com/shelljs/shelljs/pull/903) ([nfischer](https://github.com/nfischer)) +- chore\(ci\): fix codecov on travis [\#897](https://github.com/shelljs/shelljs/pull/897) ([nfischer](https://github.com/nfischer)) +- chore\(npm\): add ci-or-install script [\#896](https://github.com/shelljs/shelljs/pull/896) ([nfischer](https://github.com/nfischer)) +- Fix silent exec [\#892](https://github.com/shelljs/shelljs/pull/892) ([nfischer](https://github.com/nfischer)) +- chore\(appveyor\): run entire test matrix [\#886](https://github.com/shelljs/shelljs/pull/886) ([nfischer](https://github.com/nfischer)) +- docs: remove gitter badge [\#880](https://github.com/shelljs/shelljs/pull/880) ([nfischer](https://github.com/nfischer)) +- grep includes the i flag [\#876](https://github.com/shelljs/shelljs/pull/876) ([ppsleep](https://github.com/ppsleep)) +- Fix\(which\): match only executable files \(\#657\) [\#874](https://github.com/shelljs/shelljs/pull/874) ([termosa](https://github.com/termosa)) +- chore: rename some tests [\#871](https://github.com/shelljs/shelljs/pull/871) ([nfischer](https://github.com/nfischer)) +- Fix cp from readonly source [\#870](https://github.com/shelljs/shelljs/pull/870) ([nfischer](https://github.com/nfischer)) +- chore: bump dev dependencies and add package-lock [\#864](https://github.com/shelljs/shelljs/pull/864) ([nfischer](https://github.com/nfischer)) +- fix\(mocks\): fix conflict between mocks and skip [\#863](https://github.com/shelljs/shelljs/pull/863) ([nfischer](https://github.com/nfischer)) +- chore: output npm version in travis [\#850](https://github.com/shelljs/shelljs/pull/850) ([nfischer](https://github.com/nfischer)) +- Prevent require-ing bin/shjs [\#848](https://github.com/shelljs/shelljs/pull/848) ([freitagbr](https://github.com/freitagbr)) +- chore\(appveyor\): do not use latest npm [\#847](https://github.com/shelljs/shelljs/pull/847) ([nfischer](https://github.com/nfischer)) +- chore: update shelljs-release version [\#846](https://github.com/shelljs/shelljs/pull/846) ([nfischer](https://github.com/nfischer)) + ## [v0.8.2](https://github.com/shelljs/shelljs/tree/v0.8.2) (2018-05-08) [Full Changelog](https://github.com/shelljs/shelljs/compare/v0.8.1...v0.8.2) @@ -28,7 +79,6 @@ **Closed issues:** - Exec failing with internal error when piping large output [\#818](https://github.com/shelljs/shelljs/issues/818) -- using sed to replace just the first occurrence of a string [\#813](https://github.com/shelljs/shelljs/issues/813) **Merged pull requests:** @@ -167,7 +217,6 @@ - Add support for other file types in rm [\#617](https://github.com/shelljs/shelljs/issues/617) - Feature request: ls -L option [\#563](https://github.com/shelljs/shelljs/issues/563) - How to send SIGINT signal to child process launched with exec [\#518](https://github.com/shelljs/shelljs/issues/518) -- exec doesnt seem to be working [\#480](https://github.com/shelljs/shelljs/issues/480) - feature request: option to add node\_modules to the path for shelljs scripts [\#469](https://github.com/shelljs/shelljs/issues/469) - high cpu usage during synchronous exec [\#167](https://github.com/shelljs/shelljs/issues/167) From db317bf09236b8cabfa6a18b232a02035e9e08f1 Mon Sep 17 00:00:00 2001 From: Will Yardley Date: Mon, 12 Nov 2018 20:46:10 -0800 Subject: [PATCH 66/71] Add test case for sed on empty file (#904) As discussed as an aside in #900, add test case with an empty file. --- test/resources/sed/empty.txt | 0 test/sed.js | 6 ++++++ 2 files changed, 6 insertions(+) create mode 100644 test/resources/sed/empty.txt diff --git a/test/resources/sed/empty.txt b/test/resources/sed/empty.txt new file mode 100644 index 000000000..e69de29bb diff --git a/test/sed.js b/test/sed.js index fc65c5412..b2dc655aa 100644 --- a/test/sed.js +++ b/test/sed.js @@ -174,3 +174,9 @@ test('glob file names, with in-place-replacement', t => { t.is(shell.cat(`${t.context.tmp}/file1.txt`).toString(), 'hello1\n'); t.is(shell.cat(`${t.context.tmp}/file2.txt`).toString(), 'hello2\n'); }); + +test('empty file', t => { + const result = shell.sed('widget', 'wizzle', 'test/resources/sed/empty.txt'); + t.is(result.code, 0); + t.is(result.toString(), ''); +}); From d4d1317ce62531fbd49085852b8492db3dd39312 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 12 Nov 2018 20:49:46 -0800 Subject: [PATCH 67/71] 0.8.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4a3d67b5a..3cca706bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.8.2", + "version": "0.8.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c4e8a551e..fcb0fb570 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.8.2", + "version": "0.8.3", "description": "Portable Unix shell commands for Node.js", "keywords": [ "shelljs", From a1111ee793e0292e4eff27b69214b361bd1eb712 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 21 Oct 2019 00:17:10 +0200 Subject: [PATCH 68/71] Silence potentially upcoming circular dependency warning (#973) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Node.js is currently considering printing a warning when a non-existent property of `module.exports` is accessed while in a circular `require()` dependency, in order to make it easier to catch issues with circular dependencies. In order to avoid printing these warnings for shelljs, checking for the property’s existence rather than its truthiness suffices. Refs: https://github.com/nodejs/node/pull/29935 --- src/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.js b/src/common.js index 14a49fc58..64fa2fbc0 100644 --- a/src/common.js +++ b/src/common.js @@ -450,7 +450,7 @@ function _register(name, implementation, wrapOptions) { // If an option isn't specified, use the default wrapOptions = Object.assign({}, DEFAULT_WRAP_OPTIONS, wrapOptions); - if (shell[name]) { + if (shell.hasOwnProperty(name)) { throw new Error('Command `' + name + '` already exists'); } From fcf1651be9a3bb8e20ba1fd24b8a91f369829c53 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Fri, 24 Apr 2020 20:58:18 -0700 Subject: [PATCH 69/71] 0.8.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3cca706bd..3ea3c3e54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.8.3", + "version": "0.8.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index fcb0fb570..b52070538 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.8.3", + "version": "0.8.4", "description": "Portable Unix shell commands for Node.js", "keywords": [ "shelljs", From d919d22dd6de385edaa9d90313075a77f74b338c Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 6 Jan 2022 21:14:23 -0800 Subject: [PATCH 70/71] fix(exec): lockdown file permissions (#1060) This locks down file permissions used by the internal implementation of `shell.exec()`. Issue #1058 Tested manually using the documented scenarios --- src/exec.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/exec.js b/src/exec.js index de3322c81..78faf13d2 100644 --- a/src/exec.js +++ b/src/exec.js @@ -48,7 +48,24 @@ function execSync(cmd, opts, pipe) { stderrFile: stderrFile, }; - fs.writeFileSync(paramsFile, JSON.stringify(paramsToSerialize), 'utf8'); + // Create the files and ensure these are locked down (for read and write) to + // the current user. The main concerns here are: + // + // * If we execute a command which prints sensitive output, then + // stdoutFile/stderrFile must not be readable by other users. + // * paramsFile must not be readable by other users, or else they can read it + // to figure out the path for stdoutFile/stderrFile and create these first + // (locked down to their own access), which will crash exec() when it tries + // to write to the files. + function writeFileLockedDown(filePath, data) { + fs.writeFileSync(filePath, data, { + encoding: 'utf8', + mode: parseInt('600', 8), + }); + } + writeFileLockedDown(stdoutFile, ''); + writeFileLockedDown(stderrFile, ''); + writeFileLockedDown(paramsFile, JSON.stringify(paramsToSerialize)); var execArgs = [ path.join(__dirname, 'exec-child.js'), @@ -91,6 +108,7 @@ function execSync(cmd, opts, pipe) { } // No biggie if we can't erase the files now -- they're in a temp dir anyway + // and we locked down permissions (see the note above). try { common.unlinkSync(paramsFile); } catch (e) {} try { common.unlinkSync(stderrFile); } catch (e) {} try { common.unlinkSync(stdoutFile); } catch (e) {} From 70668a4555c7d49c4f67d53ea063b899be4d6d40 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Thu, 6 Jan 2022 21:31:45 -0800 Subject: [PATCH 71/71] 0.8.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3ea3c3e54..178dc7a1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.8.4", + "version": "0.8.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b52070538..5c79efeec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.8.4", + "version": "0.8.5", "description": "Portable Unix shell commands for Node.js", "keywords": [ "shelljs",