From 65901129b3ae0aada456c79e7b35effee74af5bf Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Sun, 8 Jan 2017 14:35:42 -0800 Subject: [PATCH 001/108] docs(changelog): updated by Brandon Freitag [ci skip] --- CHANGELOG.md | 701 +-------------------------------------------------- 1 file changed, 1 insertion(+), 700 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 445ce626f..b8d7ab214 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,700 +1 @@ -# Change Log - -## [Unreleased](https://github.com/shelljs/shelljs/tree/HEAD) - -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.5...HEAD) - -**Closed issues:** - -- QUESTION: Feedback while an operation is running? [\#629](https://github.com/shelljs/shelljs/issues/629) -- Test setup/cleanup is broken [\#621](https://github.com/shelljs/shelljs/issues/621) -- Ignore temp directories when running lint [\#620](https://github.com/shelljs/shelljs/issues/620) -- parseOptions should throw an error if the option string doesn't start with '-' [\#614](https://github.com/shelljs/shelljs/issues/614) -- chore: LGTM.co is gone [\#595](https://github.com/shelljs/shelljs/issues/595) -- refactor: objectAssign should refer to Object.assign if it exists, or the internal polyfill otherwise [\#592](https://github.com/shelljs/shelljs/issues/592) -- parseOptions: allow a way to keep errors silent \(exception only\) [\#591](https://github.com/shelljs/shelljs/issues/591) -- \[Question\] commands with multiple options / arguments? [\#589](https://github.com/shelljs/shelljs/issues/589) -- feature: GNU Parallel [\#585](https://github.com/shelljs/shelljs/issues/585) -- 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) -- 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) -- 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) -- Add a way to prevent shell-expansion on commands \(this issue is not for exec\) [\#345](https://github.com/shelljs/shelljs/issues/345) -- Chown [\#183](https://github.com/shelljs/shelljs/issues/183) -- spawn EMFILE [\#81](https://github.com/shelljs/shelljs/issues/81) -- Rewrite exec using execsync-ng \(which uses node-ffi\) [\#66](https://github.com/shelljs/shelljs/issues/66) -- `exec` gets stuck on my Debian box [\#51](https://github.com/shelljs/shelljs/issues/51) -- 100% cpu usage when a nodejs script goes side ways executing a command. [\#5](https://github.com/shelljs/shelljs/issues/5) - -**Merged pull requests:** - -- Finalize moving to ava [\#630](https://github.com/shelljs/shelljs/pull/630) ([freitagbr](https://github.com/freitagbr)) -- test: refactor pushd tests to AVA [\#627](https://github.com/shelljs/shelljs/pull/627) ([nfischer](https://github.com/nfischer)) -- test: refactor popd tests to AVA [\#626](https://github.com/shelljs/shelljs/pull/626) ([nfischer](https://github.com/nfischer)) -- test: refactor shjs tests to AVA [\#625](https://github.com/shelljs/shelljs/pull/625) ([nfischer](https://github.com/nfischer)) -- test: remove tests for make \(deprecated\) [\#624](https://github.com/shelljs/shelljs/pull/624) ([nfischer](https://github.com/nfischer)) -- Ignore test temp directories during linting [\#623](https://github.com/shelljs/shelljs/pull/623) ([freitagbr](https://github.com/freitagbr)) -- refactor: list all commands in commands.json [\#616](https://github.com/shelljs/shelljs/pull/616) ([nfischer](https://github.com/nfischer)) -- Throw an error if the options string does not start with '-' [\#615](https://github.com/shelljs/shelljs/pull/615) ([freitagbr](https://github.com/freitagbr)) -- chore: switch to files attribute from npmignore [\#613](https://github.com/shelljs/shelljs/pull/613) ([nfischer](https://github.com/nfischer)) -- test: refactor 'test' command tests to AVA [\#612](https://github.com/shelljs/shelljs/pull/612) ([nfischer](https://github.com/nfischer)) -- test: refactor find tests to AVA [\#611](https://github.com/shelljs/shelljs/pull/611) ([nfischer](https://github.com/nfischer)) -- test: refactor ln tests to AVA [\#610](https://github.com/shelljs/shelljs/pull/610) ([nfischer](https://github.com/nfischer)) -- test: refactor ls to use AVA [\#609](https://github.com/shelljs/shelljs/pull/609) ([nfischer](https://github.com/nfischer)) -- test: refactor pipe tests to AVA [\#608](https://github.com/shelljs/shelljs/pull/608) ([nfischer](https://github.com/nfischer)) -- test: refactor sed tests to AVA [\#607](https://github.com/shelljs/shelljs/pull/607) ([nfischer](https://github.com/nfischer)) -- test: refactor grep tests to AVA [\#606](https://github.com/shelljs/shelljs/pull/606) ([nfischer](https://github.com/nfischer)) -- test: refactor global tests to AVA [\#605](https://github.com/shelljs/shelljs/pull/605) ([nfischer](https://github.com/nfischer)) -- test: refactor touch tests to AVA [\#604](https://github.com/shelljs/shelljs/pull/604) ([nfischer](https://github.com/nfischer)) -- test: refactor uniq tests to AVA [\#603](https://github.com/shelljs/shelljs/pull/603) ([nfischer](https://github.com/nfischer)) -- test: refactor sort tests to AVA [\#602](https://github.com/shelljs/shelljs/pull/602) ([nfischer](https://github.com/nfischer)) -- test: refactor tail tests to AVA [\#601](https://github.com/shelljs/shelljs/pull/601) ([nfischer](https://github.com/nfischer)) -- test: refactor head tests to AVA [\#600](https://github.com/shelljs/shelljs/pull/600) ([nfischer](https://github.com/nfischer)) -- test: refactor mkdir tests to AVA [\#599](https://github.com/shelljs/shelljs/pull/599) ([nfischer](https://github.com/nfischer)) -- Fix: rm behavior regarding symlinks [\#598](https://github.com/shelljs/shelljs/pull/598) ([freitagbr](https://github.com/freitagbr)) -- test: refactor mv tests to AVA [\#597](https://github.com/shelljs/shelljs/pull/597) ([nfischer](https://github.com/nfischer)) -- Remove files related to lgtm.co [\#596](https://github.com/shelljs/shelljs/pull/596) ([freitagbr](https://github.com/freitagbr)) -- Add ability to configure error from parseOptions [\#594](https://github.com/shelljs/shelljs/pull/594) ([freitagbr](https://github.com/freitagbr)) -- Use Object.assign if possible [\#593](https://github.com/shelljs/shelljs/pull/593) ([freitagbr](https://github.com/freitagbr)) -- Add "-n" option to echo [\#590](https://github.com/shelljs/shelljs/pull/590) ([freitagbr](https://github.com/freitagbr)) -- test: refactor rm tests to AVA [\#586](https://github.com/shelljs/shelljs/pull/586) ([nfischer](https://github.com/nfischer)) -- test: refactor pwd tests to AVA [\#582](https://github.com/shelljs/shelljs/pull/582) ([nfischer](https://github.com/nfischer)) -- test: refactor tempdir tests to AVA [\#581](https://github.com/shelljs/shelljs/pull/581) ([nfischer](https://github.com/nfischer)) -- test: refactor 'which' tests to AVA [\#580](https://github.com/shelljs/shelljs/pull/580) ([nfischer](https://github.com/nfischer)) -- test: refactor plugin tests to AVA [\#579](https://github.com/shelljs/shelljs/pull/579) ([nfischer](https://github.com/nfischer)) -- test: refactor toEnd tests to AVA [\#578](https://github.com/shelljs/shelljs/pull/578) ([nfischer](https://github.com/nfischer)) -- test: refactor to tests to AVA [\#577](https://github.com/shelljs/shelljs/pull/577) ([nfischer](https://github.com/nfischer)) -- test: refactor 'set' tests to AVA [\#576](https://github.com/shelljs/shelljs/pull/576) ([nfischer](https://github.com/nfischer)) -- test: refactor echo tests to AVA [\#575](https://github.com/shelljs/shelljs/pull/575) ([nfischer](https://github.com/nfischer)) -- test: refactor exec tests to AVA [\#574](https://github.com/shelljs/shelljs/pull/574) ([nfischer](https://github.com/nfischer)) -- test: refactor env tests to AVA [\#573](https://github.com/shelljs/shelljs/pull/573) ([nfischer](https://github.com/nfischer)) -- test: refactor dirs tests to AVA [\#572](https://github.com/shelljs/shelljs/pull/572) ([nfischer](https://github.com/nfischer)) -- test: refactor config tests to AVA [\#571](https://github.com/shelljs/shelljs/pull/571) ([nfischer](https://github.com/nfischer)) -- test: refactor common tests to AVA [\#570](https://github.com/shelljs/shelljs/pull/570) ([nfischer](https://github.com/nfischer)) -- test: refactor chmod tests to AVA [\#569](https://github.com/shelljs/shelljs/pull/569) ([nfischer](https://github.com/nfischer)) -- test: refactor cp tests to ava [\#565](https://github.com/shelljs/shelljs/pull/565) ([nfischer](https://github.com/nfischer)) -- test: refactor cat tests to ava [\#564](https://github.com/shelljs/shelljs/pull/564) ([nfischer](https://github.com/nfischer)) -- test: set up ava and move cd.js [\#561](https://github.com/shelljs/shelljs/pull/561) ([nfischer](https://github.com/nfischer)) -- Update sed documentation regarding capture groups [\#558](https://github.com/shelljs/shelljs/pull/558) ([freitagbr](https://github.com/freitagbr)) -- Add newline to output of echo [\#557](https://github.com/shelljs/shelljs/pull/557) ([freitagbr](https://github.com/freitagbr)) -- fix: handle code-less errors more carefully in exec [\#554](https://github.com/shelljs/shelljs/pull/554) ([nfischer](https://github.com/nfischer)) -- 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)) - -## [v0.7.5](https://github.com/shelljs/shelljs/tree/v0.7.5) (2016-10-27) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.4...v0.7.5) - -**Closed issues:** - -- Project objectives: there is some higher goal to achieve? [\#533](https://github.com/shelljs/shelljs/issues/533) -- fs.existsSync is un-deprecated [\#531](https://github.com/shelljs/shelljs/issues/531) -- Inadvertent breaking change to shell.test\(\) [\#529](https://github.com/shelljs/shelljs/issues/529) -- Add -u flag support for cp [\#526](https://github.com/shelljs/shelljs/issues/526) -- API request: allow `plugin.error\(\)` to take an options parameter [\#522](https://github.com/shelljs/shelljs/issues/522) -- FS Real Path error thrown when requiring shelljs [\#521](https://github.com/shelljs/shelljs/issues/521) -- Question: passing code via pipe? [\#520](https://github.com/shelljs/shelljs/issues/520) -- The performance in `cp` is different between `0.6.0` and `0.7.4` [\#517](https://github.com/shelljs/shelljs/issues/517) -- 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:** - -- feat: plugin.error\(\) takes an options parameter [\#535](https://github.com/shelljs/shelljs/pull/535) ([nfischer](https://github.com/nfischer)) -- Revert "refactor: replace fs.existsSync" fixes\(\#531\) [\#532](https://github.com/shelljs/shelljs/pull/532) ([gyandeeps](https://github.com/gyandeeps)) -- Fix: Remove default glob from shell.test \(fixes \#529\) [\#530](https://github.com/shelljs/shelljs/pull/530) ([gyandeeps](https://github.com/gyandeeps)) -- feat: cp -u option [\#527](https://github.com/shelljs/shelljs/pull/527) ([nfischer](https://github.com/nfischer)) -- chore: add downloads per month on README [\#513](https://github.com/shelljs/shelljs/pull/513) ([nfischer](https://github.com/nfischer)) - -## [v0.7.4](https://github.com/shelljs/shelljs/tree/v0.7.4) (2016-08-26) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.3...v0.7.4) - -**Closed issues:** - -- fix: echo -e should not print "-e" [\#510](https://github.com/shelljs/shelljs/issues/510) -- Wrong method signature in doc [\#498](https://github.com/shelljs/shelljs/issues/498) -- readFromPipe should be a function with no arguments [\#485](https://github.com/shelljs/shelljs/issues/485) -- TypeError: Cannot read property 'toString' of undefined [\#471](https://github.com/shelljs/shelljs/issues/471) - -**Merged pull requests:** - -- fix: echo supports -e option properly [\#511](https://github.com/shelljs/shelljs/pull/511) ([nfischer](https://github.com/nfischer)) -- refactor: replace fs.existsSync [\#509](https://github.com/shelljs/shelljs/pull/509) ([nfischer](https://github.com/nfischer)) -- refactor: readFromPipe\(\) requires no arguments [\#506](https://github.com/shelljs/shelljs/pull/506) ([nfischer](https://github.com/nfischer)) -- chore: switch to eslint [\#504](https://github.com/shelljs/shelljs/pull/504) ([nfischer](https://github.com/nfischer)) -- feat: add overWrite option for commands [\#503](https://github.com/shelljs/shelljs/pull/503) ([nfischer](https://github.com/nfischer)) -- chore: update issue template [\#502](https://github.com/shelljs/shelljs/pull/502) ([nfischer](https://github.com/nfischer)) -- fixed head/tail readme [\#499](https://github.com/shelljs/shelljs/pull/499) ([charlesread](https://github.com/charlesread)) - -## [v0.7.3](https://github.com/shelljs/shelljs/tree/v0.7.3) (2016-07-27) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.2...v0.7.3) - -**Closed issues:** - -- expose execSync [\#494](https://github.com/shelljs/shelljs/issues/494) -- Add a way to create commands that can receive from a pipe without being standalone commands [\#487](https://github.com/shelljs/shelljs/issues/487) -- cp -r breaks when the directory contains a softlink [\#193](https://github.com/shelljs/shelljs/issues/193) -- Redirect output to file fails [\#60](https://github.com/shelljs/shelljs/issues/60) -- We need sed -n ? [\#38](https://github.com/shelljs/shelljs/issues/38) - -**Merged pull requests:** - -- refactor: allow pipeOnly commands \(methods on ShellStrings\) [\#493](https://github.com/shelljs/shelljs/pull/493) ([nfischer](https://github.com/nfischer)) -- refactor: glob by default for commands [\#492](https://github.com/shelljs/shelljs/pull/492) ([nfischer](https://github.com/nfischer)) -- refactor: switch from notUnix to unix in wrap\(\) [\#491](https://github.com/shelljs/shelljs/pull/491) ([nfischer](https://github.com/nfischer)) -- refactor: switch common.extend\(\) to Object.assign ponyfill [\#490](https://github.com/shelljs/shelljs/pull/490) ([nfischer](https://github.com/nfischer)) -- fix: conflicting options now properly override each other [\#489](https://github.com/shelljs/shelljs/pull/489) ([nfischer](https://github.com/nfischer)) -- refactor: expose plugin utils & add initial tests [\#484](https://github.com/shelljs/shelljs/pull/484) ([nfischer](https://github.com/nfischer)) - -## [v0.7.2](https://github.com/shelljs/shelljs/tree/v0.7.2) (2016-07-25) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.1...v0.7.2) - -**Closed issues:** - -- shelljs should not kill process if node call throws exception [\#473](https://github.com/shelljs/shelljs/issues/473) -- `cp` work incorrectly when folder name contains '@' [\#463](https://github.com/shelljs/shelljs/issues/463) -- Something went wrong [\#158](https://github.com/shelljs/shelljs/issues/158) - -**Merged pull requests:** - -- fix: resolve a cylcic-dependency problem [\#482](https://github.com/shelljs/shelljs/pull/482) ([nfischer](https://github.com/nfischer)) -- refactor: add wrapOutput option to auto-ShellString-ify command output [\#481](https://github.com/shelljs/shelljs/pull/481) ([nfischer](https://github.com/nfischer)) -- refactor: move option parsing into common.wrap\(\) [\#479](https://github.com/shelljs/shelljs/pull/479) ([nfischer](https://github.com/nfischer)) -- refactor: hook new uniq\(\) command using new format [\#478](https://github.com/shelljs/shelljs/pull/478) ([nfischer](https://github.com/nfischer)) -- Fix mkdir malformed path [\#477](https://github.com/shelljs/shelljs/pull/477) ([nfischer](https://github.com/nfischer)) -- fix: mkdir for invalid perms does not kill process [\#474](https://github.com/shelljs/shelljs/pull/474) ([nfischer](https://github.com/nfischer)) -- feat\(command\): new command: uniq\(\) [\#453](https://github.com/shelljs/shelljs/pull/453) ([joshi-sh](https://github.com/joshi-sh)) - -## [v0.7.1](https://github.com/shelljs/shelljs/tree/v0.7.1) (2016-07-22) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.0...v0.7.1) - -**Closed issues:** - -- cp -n doesn't work correctly [\#465](https://github.com/shelljs/shelljs/issues/465) -- how can i run sudo apt-get install xtodotool by your plugin? [\#448](https://github.com/shelljs/shelljs/issues/448) -- shell.js grep: internal error, Invalid regular expression [\#447](https://github.com/shelljs/shelljs/issues/447) -- 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:** - -- refactor: commands now register themselves [\#475](https://github.com/shelljs/shelljs/pull/475) ([nfischer](https://github.com/nfischer)) -- chore: switch to shields.io, and add npm badge [\#470](https://github.com/shelljs/shelljs/pull/470) ([nfischer](https://github.com/nfischer)) -- fix\(cp\): -n option no longer raises error [\#466](https://github.com/shelljs/shelljs/pull/466) ([nfischer](https://github.com/nfischer)) -- refactor: expose pipe-ability to command configuration [\#464](https://github.com/shelljs/shelljs/pull/464) ([nfischer](https://github.com/nfischer)) -- fix\(mv\): works across partitions [\#461](https://github.com/shelljs/shelljs/pull/461) ([nfischer](https://github.com/nfischer)) -- chore: switch to shelljs-changelog [\#460](https://github.com/shelljs/shelljs/pull/460) ([nfischer](https://github.com/nfischer)) -- chore: update release process [\#459](https://github.com/shelljs/shelljs/pull/459) ([nfischer](https://github.com/nfischer)) -- chore: revert depreciate shelljs/make \(\#431\) [\#458](https://github.com/shelljs/shelljs/pull/458) ([zephraph](https://github.com/zephraph)) -- chore: clarify message for when docs are not generated [\#457](https://github.com/shelljs/shelljs/pull/457) ([nfischer](https://github.com/nfischer)) -- chore\(gendocs\): add `npm run gendocs` command [\#455](https://github.com/shelljs/shelljs/pull/455) ([nfischer](https://github.com/nfischer)) -- chore: update jshint and move it to an npm script [\#454](https://github.com/shelljs/shelljs/pull/454) ([nfischer](https://github.com/nfischer)) -- test\(ls\): add case for trailing slash on dir name [\#450](https://github.com/shelljs/shelljs/pull/450) ([nfischer](https://github.com/nfischer)) -- docs\(exec\): explicitly mention the `shell` option [\#449](https://github.com/shelljs/shelljs/pull/449) ([nfischer](https://github.com/nfischer)) -- chore: setup changelog [\#443](https://github.com/shelljs/shelljs/pull/443) ([levithomason](https://github.com/levithomason)) -- 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) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.6.0...v0.7.0) - -**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) -- Refactor more commands to return ShellString [\#373](https://github.com/shelljs/shelljs/issues/373) -- ln\('-sf', './', '\'\) is not linking the right folder [\#363](https://github.com/shelljs/shelljs/issues/363) -- v0.6.0 - shell.cp\('r', '/foo/\*, '/bar'\) fails with /foo/\* no such file or directory [\#342](https://github.com/shelljs/shelljs/issues/342) -- Add documentup as a webhook [\#327](https://github.com/shelljs/shelljs/issues/327) -- Dir glob breaks when in the middle of path [\#245](https://github.com/shelljs/shelljs/issues/245) -- could you switch off wiki page? [\#233](https://github.com/shelljs/shelljs/issues/233) -- ls globbing does not behave like shell, consider using glob.sync [\#225](https://github.com/shelljs/shelljs/issues/225) -- Cannot run shell.exec\('heroku config:push'\) -- just hangs [\#218](https://github.com/shelljs/shelljs/issues/218) -- `cp` does not overwrite files by default [\#210](https://github.com/shelljs/shelljs/issues/210) -- exec failed to return [\#208](https://github.com/shelljs/shelljs/issues/208) -- CLI Version [\#202](https://github.com/shelljs/shelljs/issues/202) -- Bracket expansion not working [\#176](https://github.com/shelljs/shelljs/issues/176) -- "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) -- Only get stdout from `exec` [\#92](https://github.com/shelljs/shelljs/issues/92) -- What about other commands? [\#90](https://github.com/shelljs/shelljs/issues/90) -- Flesh out example of exit\(\) [\#73](https://github.com/shelljs/shelljs/issues/73) -- exec doesn't work with qualified paths on windows [\#41](https://github.com/shelljs/shelljs/issues/41) -- exec does not working in mingw bash in windows [\#17](https://github.com/shelljs/shelljs/issues/17) -- Add support for cp -P option [\#413](https://github.com/shelljs/shelljs/issues/413) -- cp -L: Incorrect behavior for symlinks to regular files [\#407](https://github.com/shelljs/shelljs/issues/407) -- Edit the docs to emphasize ShellStrings and Pipes [\#398](https://github.com/shelljs/shelljs/issues/398) -- Error message isn't always printed [\#372](https://github.com/shelljs/shelljs/issues/372) -- Standardize command output [\#356](https://github.com/shelljs/shelljs/issues/356) -- exec\(\) doesn't clean up all temp files [\#353](https://github.com/shelljs/shelljs/issues/353) -- Document that exec\(\) options don't work on early versions of node [\#350](https://github.com/shelljs/shelljs/issues/350) -- Add -f option to set\(\) [\#344](https://github.com/shelljs/shelljs/issues/344) -- Glob commands by default [\#343](https://github.com/shelljs/shelljs/issues/343) -- rm -rf incorrect behaviour [\#332](https://github.com/shelljs/shelljs/issues/332) -- Switch `exec\(\)` to use bash by default [\#281](https://github.com/shelljs/shelljs/issues/281) -- pipe to proc [\#148](https://github.com/shelljs/shelljs/issues/148) -- shell builtin [\#138](https://github.com/shelljs/shelljs/issues/138) -- add timeout option for exec [\#132](https://github.com/shelljs/shelljs/issues/132) -- shelljs cp handling symlinks badly [\#69](https://github.com/shelljs/shelljs/issues/69) - -**Merged pull requests:** - -- chore: add "Team" section to README [\#423](https://github.com/shelljs/shelljs/pull/423) ([nfischer](https://github.com/nfischer)) -- Contributing guidelines [\#422](https://github.com/shelljs/shelljs/pull/422) ([nfischer](https://github.com/nfischer)) -- feat\(glob\): expose config.globOptions. [\#400](https://github.com/shelljs/shelljs/pull/400) ([nfischer](https://github.com/nfischer)) -- Add shelljs as a keyword in package.json [\#393](https://github.com/shelljs/shelljs/pull/393) ([nfischer](https://github.com/nfischer)) -- docs: add link to wiki page [\#392](https://github.com/shelljs/shelljs/pull/392) ([nfischer](https://github.com/nfischer)) -- refactor\(cd\): use process.env.OLDPWD to store previous dir [\#383](https://github.com/shelljs/shelljs/pull/383) ([nfischer](https://github.com/nfischer)) -- chore\(appveyor\): add in node 4 for appveyor [\#381](https://github.com/shelljs/shelljs/pull/381) ([nfischer](https://github.com/nfischer)) -- Add Cash cross-reference [\#375](https://github.com/shelljs/shelljs/pull/375) ([dthree](https://github.com/dthree)) -- Ignore gitattributes from npm package [\#361](https://github.com/shelljs/shelljs/pull/361) ([nfischer](https://github.com/nfischer)) -- Consistently use LF line endings [\#355](https://github.com/shelljs/shelljs/pull/355) ([TimothyGu](https://github.com/TimothyGu)) -- Release v0.7.0 [\#429](https://github.com/shelljs/shelljs/pull/429) ([nfischer](https://github.com/nfischer)) -- fix: null is no longer confused for an object [\#428](https://github.com/shelljs/shelljs/pull/428) ([nfischer](https://github.com/nfischer)) -- fix\(ls\): no trailing newline for empty directories [\#425](https://github.com/shelljs/shelljs/pull/425) ([nfischer](https://github.com/nfischer)) -- feat\(cp\): -P option, plus better handling of symlinks [\#421](https://github.com/shelljs/shelljs/pull/421) ([nfischer](https://github.com/nfischer)) -- docs\(exec\): fix docs about exec return type [\#419](https://github.com/shelljs/shelljs/pull/419) ([nfischer](https://github.com/nfischer)) -- docs\(error\): deprecate relying on string value [\#418](https://github.com/shelljs/shelljs/pull/418) ([nfischer](https://github.com/nfischer)) -- fix: error message now printed for fatal failures [\#417](https://github.com/shelljs/shelljs/pull/417) ([nfischer](https://github.com/nfischer)) -- issue-407: Add regular files unit tests and fix symlink copy behavior [\#409](https://github.com/shelljs/shelljs/pull/409) ([charlesverge](https://github.com/charlesverge)) -- refactor\(rm\): Remove duplicate code [\#408](https://github.com/shelljs/shelljs/pull/408) ([nfischer](https://github.com/nfischer)) -- docs: wildcards for all commands, other docs cleanups [\#404](https://github.com/shelljs/shelljs/pull/404) ([nfischer](https://github.com/nfischer)) -- test\(rm\): add tests to prevent a future regression [\#403](https://github.com/shelljs/shelljs/pull/403) ([nfischer](https://github.com/nfischer)) -- refactor\(string\): modify string protoype, but only for shelljs/global [\#401](https://github.com/shelljs/shelljs/pull/401) ([nfischer](https://github.com/nfischer)) -- feat: adding error codes to ShellJS [\#394](https://github.com/shelljs/shelljs/pull/394) ([nfischer](https://github.com/nfischer)) -- feature: use rechoir [\#384](https://github.com/shelljs/shelljs/pull/384) ([nfischer](https://github.com/nfischer)) -- refactor\(cp\): clean up code and fix \#376 [\#380](https://github.com/shelljs/shelljs/pull/380) ([nfischer](https://github.com/nfischer)) -- New commands: sort\(\), head\(\), and tail\(\) [\#379](https://github.com/shelljs/shelljs/pull/379) ([nfischer](https://github.com/nfischer)) -- Add unit tests to prevent regression \(see \#376\) [\#378](https://github.com/shelljs/shelljs/pull/378) ([nfischer](https://github.com/nfischer)) -- feat\(pipe\): add support for pipes between commands [\#370](https://github.com/shelljs/shelljs/pull/370) ([nfischer](https://github.com/nfischer)) -- refactor\(ls\): greatly simplify ls implimentation [\#369](https://github.com/shelljs/shelljs/pull/369) ([ariporad](https://github.com/ariporad)) -- chore: drop node v0.10 support [\#368](https://github.com/shelljs/shelljs/pull/368) ([ariporad](https://github.com/ariporad)) -- perf\(cd\): only run `stat` once [\#367](https://github.com/shelljs/shelljs/pull/367) ([ariporad](https://github.com/ariporad)) -- fix\(exec\): properly handles paths with spaces and quotes [\#365](https://github.com/shelljs/shelljs/pull/365) ([nfischer](https://github.com/nfischer)) -- test\(ln\): add tests for linking to cwd [\#364](https://github.com/shelljs/shelljs/pull/364) ([nfischer](https://github.com/nfischer)) -- fix\(verbose\): verbose-style logging is consistent [\#362](https://github.com/shelljs/shelljs/pull/362) ([nfischer](https://github.com/nfischer)) -- Refactor shellstring [\#360](https://github.com/shelljs/shelljs/pull/360) ([nfischer](https://github.com/nfischer)) -- feat\(glob\): use glob module for globbing [\#359](https://github.com/shelljs/shelljs/pull/359) ([nfischer](https://github.com/nfischer)) -- feat\(set\): add -f option to disable globbing [\#358](https://github.com/shelljs/shelljs/pull/358) ([nfischer](https://github.com/nfischer)) -- config.fatal now throws an exception [\#357](https://github.com/shelljs/shelljs/pull/357) ([jrmclaurin](https://github.com/jrmclaurin)) -- fix\(exec\): temp files are now cleaned up [\#354](https://github.com/shelljs/shelljs/pull/354) ([nfischer](https://github.com/nfischer)) -- feat\(glob\): glob support for \(almost\) all commands [\#352](https://github.com/shelljs/shelljs/pull/352) ([nfischer](https://github.com/nfischer)) -- feat\(grep\): add -l option [\#349](https://github.com/shelljs/shelljs/pull/349) ([nfischer](https://github.com/nfischer)) -- fix\(exec\): now actually supports shell option [\#348](https://github.com/shelljs/shelljs/pull/348) ([nfischer](https://github.com/nfischer)) -- feat\(touch\): supports multiple files [\#346](https://github.com/shelljs/shelljs/pull/346) ([nfischer](https://github.com/nfischer)) - -## [v0.6.0](https://github.com/shelljs/shelljs/tree/v0.6.0) (2016-02-05) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.5.3...v0.6.0) - -**Closed issues:** - -- option not recognized [\#334](https://github.com/shelljs/shelljs/issues/334) -- Feature request: Metadata with `ls` [\#323](https://github.com/shelljs/shelljs/issues/323) -- Gen-docs is broken [\#309](https://github.com/shelljs/shelljs/issues/309) -- `link -s` is broken for files on Windows [\#301](https://github.com/shelljs/shelljs/issues/301) -- Shelljs quits unexpectedly: [\#300](https://github.com/shelljs/shelljs/issues/300) -- Failing tests on Windows [\#296](https://github.com/shelljs/shelljs/issues/296) -- run-tests.js is broken for cmd.exe [\#294](https://github.com/shelljs/shelljs/issues/294) -- Support echo-ing environment variables [\#291](https://github.com/shelljs/shelljs/issues/291) -- Add Windows CI [\#287](https://github.com/shelljs/shelljs/issues/287) -- Add tests for the shjs utility [\#280](https://github.com/shelljs/shelljs/issues/280) -- Allow shjs utility to infer the extension for "filename." [\#278](https://github.com/shelljs/shelljs/issues/278) -- Ability to read the stdout buffer line-by-line [\#277](https://github.com/shelljs/shelljs/issues/277) -- Poor output for commands with multiple errors [\#267](https://github.com/shelljs/shelljs/issues/267) -- Travis ci build status says "unknown" [\#266](https://github.com/shelljs/shelljs/issues/266) -- wild card characters in filename not working as expected [\#262](https://github.com/shelljs/shelljs/issues/262) -- shell.exec - read internal variable [\#260](https://github.com/shelljs/shelljs/issues/260) -- cp and rename directory with -r doesn't match unix behavior [\#256](https://github.com/shelljs/shelljs/issues/256) -- console.log.apply throwing TypeError: Illegal Invocation [\#255](https://github.com/shelljs/shelljs/issues/255) -- How to exit on first error [\#253](https://github.com/shelljs/shelljs/issues/253) -- why not support set 'cwd' when invoke execAsync ? [\#250](https://github.com/shelljs/shelljs/issues/250) -- Not possible to check the failure of cd? [\#247](https://github.com/shelljs/shelljs/issues/247) -- By default shelljs runs command in root [\#246](https://github.com/shelljs/shelljs/issues/246) -- /usr/bin/env: node: No such file or directory [\#243](https://github.com/shelljs/shelljs/issues/243) -- "Which" command not working properly on Windows Platform. [\#238](https://github.com/shelljs/shelljs/issues/238) -- Arguments [\#237](https://github.com/shelljs/shelljs/issues/237) -- 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) -- boolean return value for string.to\(\) [\#205](https://github.com/shelljs/shelljs/issues/205) -- `common.error` doesn't throw [\#199](https://github.com/shelljs/shelljs/issues/199) -- Problems with exec \(sync\) on 0.12/io.js [\#197](https://github.com/shelljs/shelljs/issues/197) -- cp --update flag [\#172](https://github.com/shelljs/shelljs/issues/172) -- Is there a way to suppress pushd/popd output? [\#171](https://github.com/shelljs/shelljs/issues/171) -- 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) -- Error ENOTEMPTY when deleting a directory recursively. [\#49](https://github.com/shelljs/shelljs/issues/49) -- Cross-platform way to add to PATH [\#32](https://github.com/shelljs/shelljs/issues/32) -- `mv` fails on block, character, fifo [\#25](https://github.com/shelljs/shelljs/issues/25) -- ls -l [\#22](https://github.com/shelljs/shelljs/issues/22) - -**Merged pull requests:** - -- feat\(set\): add new set\(\) command [\#329](https://github.com/shelljs/shelljs/pull/329) ([nfischer](https://github.com/nfischer)) -- Fix symlinking on Windows [\#322](https://github.com/shelljs/shelljs/pull/322) ([BYK](https://github.com/BYK)) -- Rewrite .gitignore to be more comprehensive [\#321](https://github.com/shelljs/shelljs/pull/321) ([BYK](https://github.com/BYK)) -- chore\(gitter/travis\): add gitter webhook to travis [\#313](https://github.com/shelljs/shelljs/pull/313) ([ariporad](https://github.com/ariporad)) -- chore\(LGTM\): add LGTM config files [\#312](https://github.com/shelljs/shelljs/pull/312) ([ariporad](https://github.com/ariporad)) -- feat\(ls\): add -d flag to ls\(\) [\#311](https://github.com/shelljs/shelljs/pull/311) ([nfischer](https://github.com/nfischer)) -- fix\(gen-docs\): fix issue where docs are generated wrong [\#310](https://github.com/shelljs/shelljs/pull/310) ([nfischer](https://github.com/nfischer)) -- chore\(package\): remove v0.8 from engines list [\#308](https://github.com/shelljs/shelljs/pull/308) ([nfischer](https://github.com/nfischer)) -- travis: Mark as not using `sudo` and do not test 0.11 [\#307](https://github.com/shelljs/shelljs/pull/307) ([TimothyGu](https://github.com/TimothyGu)) -- fix: jshint works on Windows [\#295](https://github.com/shelljs/shelljs/pull/295) ([nfischer](https://github.com/nfischer)) -- feat: add tilde expansion to expand\(\) [\#293](https://github.com/shelljs/shelljs/pull/293) ([nfischer](https://github.com/nfischer)) -- style: make docs more consistent [\#292](https://github.com/shelljs/shelljs/pull/292) ([nfischer](https://github.com/nfischer)) -- update `exec` docs to match implemented behaviour [\#289](https://github.com/shelljs/shelljs/pull/289) ([vise890](https://github.com/vise890)) -- chore: update github URL in package.json [\#288](https://github.com/shelljs/shelljs/pull/288) ([nfischer](https://github.com/nfischer)) -- docs\(spelling\): fix typo in source comment [\#285](https://github.com/shelljs/shelljs/pull/285) ([nfischer](https://github.com/nfischer)) -- chore\(travis\): add OS X to Travis CI [\#283](https://github.com/shelljs/shelljs/pull/283) ([nfischer](https://github.com/nfischer)) -- Don't do `console.log.apply\(this, ...\)`. [\#274](https://github.com/shelljs/shelljs/pull/274) ([ariporad](https://github.com/ariporad)) -- Implementing cd\('-'\) to behave like Bash's "cd -" [\#273](https://github.com/shelljs/shelljs/pull/273) ([nfischer](https://github.com/nfischer)) -- Fix cp to match unix behavior [\#271](https://github.com/shelljs/shelljs/pull/271) ([freitagbr](https://github.com/freitagbr)) -- Commands that have multiple errors now produce cleaner log output [\#268](https://github.com/shelljs/shelljs/pull/268) ([nfischer](https://github.com/nfischer)) -- Support exit code in shjs. [\#252](https://github.com/shelljs/shelljs/pull/252) ([bryce-gibson](https://github.com/bryce-gibson)) -- add touch\(1\) [\#249](https://github.com/shelljs/shelljs/pull/249) ([blockloop](https://github.com/blockloop)) -- Fix `os.tmpdir` bug [\#240](https://github.com/shelljs/shelljs/pull/240) ([BYK](https://github.com/BYK)) -- Make sure Which\(\) on Windows platform always return the command with … [\#239](https://github.com/shelljs/shelljs/pull/239) ([TingluoHuang](https://github.com/TingluoHuang)) -- Add target node.js \(iojs v1, v2, v3\) [\#230](https://github.com/shelljs/shelljs/pull/230) ([sanemat](https://github.com/sanemat)) -- feat-multisymbolic + Support for directory entry \(capital X in chmod terms\) [\#228](https://github.com/shelljs/shelljs/pull/228) ([rezonant](https://github.com/rezonant)) -- Fixes an issue with multi-symbolic mode specification \(ie a-rwx,u+rw\) [\#227](https://github.com/shelljs/shelljs/pull/227) ([rezonant](https://github.com/rezonant)) -- Memoized the result of target invocation [\#216](https://github.com/shelljs/shelljs/pull/216) ([rizowski](https://github.com/rizowski)) -- remove empty for loop and leaked i var [\#166](https://github.com/shelljs/shelljs/pull/166) ([ratbeard](https://github.com/ratbeard)) -- Wrap script name in double quotes [\#135](https://github.com/shelljs/shelljs/pull/135) ([ndelitski](https://github.com/ndelitski)) -- Fixed coffeescript syntax in top example [\#99](https://github.com/shelljs/shelljs/pull/99) ([maxnordlund](https://github.com/maxnordlund)) -- fix\(touch\): enhance parseOptions and fix touch's -r flag [\#341](https://github.com/shelljs/shelljs/pull/341) ([nfischer](https://github.com/nfischer)) -- chore\(.npmignore\): update npmignore [\#339](https://github.com/shelljs/shelljs/pull/339) ([ariporad](https://github.com/ariporad)) -- Release v0.6.0 [\#338](https://github.com/shelljs/shelljs/pull/338) ([ariporad](https://github.com/ariporad)) -- docs\(README\): remove coffeescript from README [\#337](https://github.com/shelljs/shelljs/pull/337) ([ariporad](https://github.com/ariporad)) -- fix\(cp\): add -n option, make -f default behavior [\#336](https://github.com/shelljs/shelljs/pull/336) ([nfischer](https://github.com/nfischer)) -- feat\(exec\): allow all exec options to pass through [\#335](https://github.com/shelljs/shelljs/pull/335) ([nfischer](https://github.com/nfischer)) -- fix\(mv\): add -n option, make -f default behavior [\#328](https://github.com/shelljs/shelljs/pull/328) ([nfischer](https://github.com/nfischer)) -- fix\(cat\): make behavior more like unix [\#326](https://github.com/shelljs/shelljs/pull/326) ([nfischer](https://github.com/nfischer)) -- feat\(ls\): add -l option [\#324](https://github.com/shelljs/shelljs/pull/324) ([nfischer](https://github.com/nfischer)) -- style\(test/which\): make test/which.js conform to the style guidelines [\#320](https://github.com/shelljs/shelljs/pull/320) ([ariporad](https://github.com/ariporad)) -- chore\(appveyor\): add badge [\#316](https://github.com/shelljs/shelljs/pull/316) ([nfischer](https://github.com/nfischer)) -- fix\(windows\): fix shjs commands for windows [\#315](https://github.com/shelljs/shelljs/pull/315) ([nfischer](https://github.com/nfischer)) -- feat\(sed\): support multiple file names [\#314](https://github.com/shelljs/shelljs/pull/314) ([nfischer](https://github.com/nfischer)) -- feat\(cd\): cd\(\) \(no args\) changes to home directory [\#306](https://github.com/shelljs/shelljs/pull/306) ([nfischer](https://github.com/nfischer)) -- test\(shjs\): add tests for shjs [\#304](https://github.com/shelljs/shelljs/pull/304) ([ariporad](https://github.com/ariporad)) -- fix: regexes are more consistent with sed and grep [\#303](https://github.com/shelljs/shelljs/pull/303) ([nfischer](https://github.com/nfischer)) -- Add appveyor.yml config file [\#299](https://github.com/shelljs/shelljs/pull/299) ([nfischer](https://github.com/nfischer)) -- Fix tests on Windows [\#297](https://github.com/shelljs/shelljs/pull/297) ([BYK](https://github.com/BYK)) -- Search PATHEXT instead of 3 hardcoded values [\#290](https://github.com/shelljs/shelljs/pull/290) ([isiahmeadows](https://github.com/isiahmeadows)) -- Fix relative symlinks [\#282](https://github.com/shelljs/shelljs/pull/282) ([freitagbr](https://github.com/freitagbr)) -- Make to and toEnd chainable [\#276](https://github.com/shelljs/shelljs/pull/276) ([TimothyGu](https://github.com/TimothyGu)) - -## [v0.5.3](https://github.com/shelljs/shelljs/tree/v0.5.3) (2015-08-11) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.5.2...v0.5.3) - -**Merged pull requests:** - -- Manually closing streams [\#222](https://github.com/shelljs/shelljs/pull/222) ([JulianLaval](https://github.com/JulianLaval)) - -## [v0.5.2](https://github.com/shelljs/shelljs/tree/v0.5.2) (2015-08-10) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.5.1...v0.5.2) - -**Closed issues:** - -- Cannot run shell.exec [\#217](https://github.com/shelljs/shelljs/issues/217) -- write after end: internal error [\#206](https://github.com/shelljs/shelljs/issues/206) - -**Merged pull requests:** - -- Update README.md [\#221](https://github.com/shelljs/shelljs/pull/221) ([giosh94mhz](https://github.com/giosh94mhz)) -- prevent internal error: write after end [\#214](https://github.com/shelljs/shelljs/pull/214) ([charlierudolph](https://github.com/charlierudolph)) - -## [v0.5.1](https://github.com/shelljs/shelljs/tree/v0.5.1) (2015-06-05) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.5.0...v0.5.1) - -**Closed issues:** - -- cd into home directory [\#9](https://github.com/shelljs/shelljs/issues/9) - -**Merged pull requests:** - -- Fix issue \#49: Retry rmdirSync on Windows for up to 1 second if files still exist. [\#179](https://github.com/shelljs/shelljs/pull/179) ([andreialecu](https://github.com/andreialecu)) - -## [v0.5.0](https://github.com/shelljs/shelljs/tree/v0.5.0) (2015-05-19) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.3.0...v0.5.0) - -**Closed issues:** - -- Enter text to prompt [\#203](https://github.com/shelljs/shelljs/issues/203) -- Find which shell is being used [\#195](https://github.com/shelljs/shelljs/issues/195) -- Pass command line params to the make tool [\#188](https://github.com/shelljs/shelljs/issues/188) -- Is it possible to call exec with a command containing new lines ? [\#177](https://github.com/shelljs/shelljs/issues/177) -- The installation would break on Windows 7 [\#161](https://github.com/shelljs/shelljs/issues/161) -- Q.ninvoke\(\) returns undefined [\#153](https://github.com/shelljs/shelljs/issues/153) -- installed shelljs on osx but reported error: npm ERR! 404 '%5B-g%5D' is not in the npm registry. [\#124](https://github.com/shelljs/shelljs/issues/124) -- "ln" not found \(OS X\) [\#106](https://github.com/shelljs/shelljs/issues/106) -- Using shelljs in a CLI app. [\#91](https://github.com/shelljs/shelljs/issues/91) - -**Merged pull requests:** - -- 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)) -- 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)) - -## [v0.3.0](https://github.com/shelljs/shelljs/tree/v0.3.0) (2014-05-08) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.6...v0.3.0) - -**Closed issues:** - -- grep\(\) should fully support globing [\#118](https://github.com/shelljs/shelljs/issues/118) -- sed\(\) could support replacement function [\#115](https://github.com/shelljs/shelljs/issues/115) -- How would you close an exec process that runs indefinitely? [\#113](https://github.com/shelljs/shelljs/issues/113) -- listen for intermittent output of a long-running child process [\#111](https://github.com/shelljs/shelljs/issues/111) -- Cannot find module 'shelljs' after installing shelljs with npm [\#109](https://github.com/shelljs/shelljs/issues/109) -- Massive CPU usage on exec\(\) windows [\#108](https://github.com/shelljs/shelljs/issues/108) -- cp skipping dot files? [\#79](https://github.com/shelljs/shelljs/issues/79) -- $variables in exec\(\) aren't handled correctly [\#11](https://github.com/shelljs/shelljs/issues/11) -- debug flag that prints commands instead of executing [\#8](https://github.com/shelljs/shelljs/issues/8) - -**Merged pull requests:** - -- grep\(\) support for globing, fixes \#118 [\#119](https://github.com/shelljs/shelljs/pull/119) ([utensil](https://github.com/utensil)) -- make sed\(\) support replacement function, fixes \#115 [\#117](https://github.com/shelljs/shelljs/pull/117) ([utensil](https://github.com/utensil)) -- which\(\) should only find files, not directories [\#110](https://github.com/shelljs/shelljs/pull/110) ([panrafal](https://github.com/panrafal)) -- Added the New BSD license to the package.json. [\#105](https://github.com/shelljs/shelljs/pull/105) ([keskival](https://github.com/keskival)) -- Added win32 support to ln [\#104](https://github.com/shelljs/shelljs/pull/104) ([jamon](https://github.com/jamon)) -- Fix ln using bad paths when given abspaths. [\#89](https://github.com/shelljs/shelljs/pull/89) ([Schoonology](https://github.com/Schoonology)) -- Add ln support, including both -s and -f options. [\#88](https://github.com/shelljs/shelljs/pull/88) ([Schoonology](https://github.com/Schoonology)) -- add support for symlinking \(junctions\) on win32 [\#87](https://github.com/shelljs/shelljs/pull/87) ([jamon](https://github.com/jamon)) - -## [v0.2.6](https://github.com/shelljs/shelljs/tree/v0.2.6) (2013-09-22) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.5...v0.2.6) - -**Closed issues:** - -- Versions 0.2.4 and 0.2.3 keep throwing strange errors [\#82](https://github.com/shelljs/shelljs/issues/82) -- Add global pollution tests [\#33](https://github.com/shelljs/shelljs/issues/33) - -## [v0.2.5](https://github.com/shelljs/shelljs/tree/v0.2.5) (2013-09-11) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.4...v0.2.5) - -**Closed issues:** - -- shelljs.exec stalls on Red Hat when script is invoked with 'sudo -u username' [\#72](https://github.com/shelljs/shelljs/issues/72) - -## [v0.2.4](https://github.com/shelljs/shelljs/tree/v0.2.4) (2013-09-11) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.3...v0.2.4) - -## [v0.2.3](https://github.com/shelljs/shelljs/tree/v0.2.3) (2013-09-09) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.2...v0.2.3) - -**Merged pull requests:** - -- Make shell.exec\(\) treat process error return codes as shelljs errors [\#80](https://github.com/shelljs/shelljs/pull/80) ([nilsbunger](https://github.com/nilsbunger)) - -## [v0.2.2](https://github.com/shelljs/shelljs/tree/v0.2.2) (2013-09-02) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.4...v0.2.2) - -**Closed issues:** - -- which and node\_modules [\#63](https://github.com/shelljs/shelljs/issues/63) -- cannot install with nodejs 0.10.2 [\#57](https://github.com/shelljs/shelljs/issues/57) - -**Merged pull requests:** - -- Addition of a toEnd\(\) function modeled after the Unix \>\> pipe. [\#78](https://github.com/shelljs/shelljs/pull/78) ([andreweduffy](https://github.com/andreweduffy)) -- Added appendTo\(\) function to imitate '\>\>' redirect-and-append pipe. [\#75](https://github.com/shelljs/shelljs/pull/75) ([andreweduffy](https://github.com/andreweduffy)) -- Fix a small typo in README.md [\#71](https://github.com/shelljs/shelljs/pull/71) ([asmblah](https://github.com/asmblah)) -- adding an `.npmignore` file [\#70](https://github.com/shelljs/shelljs/pull/70) ([stephenmathieson](https://github.com/stephenmathieson)) -- tempdir: use `os.tmpDir` when possible [\#67](https://github.com/shelljs/shelljs/pull/67) ([stephenmathieson](https://github.com/stephenmathieson)) - -## [v0.1.4](https://github.com/shelljs/shelljs/tree/v0.1.4) (2013-05-10) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.3...v0.1.4) - -**Merged pull requests:** - -- removing extra fs calls [\#62](https://github.com/shelljs/shelljs/pull/62) ([stephenmathieson](https://github.com/stephenmathieson)) -- moving \_jshint\_ to a development dependency [\#61](https://github.com/shelljs/shelljs/pull/61) ([stephenmathieson](https://github.com/stephenmathieson)) -- Make the maximum buffersize 20 MB. [\#59](https://github.com/shelljs/shelljs/pull/59) ([waddlesplash](https://github.com/waddlesplash)) - -## [v0.1.3](https://github.com/shelljs/shelljs/tree/v0.1.3) (2013-04-21) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.2...v0.1.3) - -**Merged pull requests:** - -- test\('-L', badlink\) should return true [\#56](https://github.com/shelljs/shelljs/pull/56) ([lge88](https://github.com/lge88)) -- exec options now allows `silent:true` with callback. [\#54](https://github.com/shelljs/shelljs/pull/54) ([iapain](https://github.com/iapain)) -- Add Zepto to README [\#53](https://github.com/shelljs/shelljs/pull/53) ([madrobby](https://github.com/madrobby)) - -## [v0.1.2](https://github.com/shelljs/shelljs/tree/v0.1.2) (2013-01-08) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.1...v0.1.2) - -**Closed issues:** - -- pushd/popd [\#24](https://github.com/shelljs/shelljs/issues/24) - -**Merged pull requests:** - -- Implemented chmod command. Github issue 35 [\#48](https://github.com/shelljs/shelljs/pull/48) ([brandonramirez](https://github.com/brandonramirez)) - -## [v0.1.1](https://github.com/shelljs/shelljs/tree/v0.1.1) (2013-01-01) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.0...v0.1.1) - -**Merged pull requests:** - -- Work in progress: pushd/popd/dirs [\#47](https://github.com/shelljs/shelljs/pull/47) ([mstade](https://github.com/mstade)) - -## [v0.1.0](https://github.com/shelljs/shelljs/tree/v0.1.0) (2012-12-26) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.9...v0.1.0) - -**Closed issues:** - -- test\(\) for binary file? [\#45](https://github.com/shelljs/shelljs/issues/45) -- Inconsistent behaviour of cp command with directories. [\#44](https://github.com/shelljs/shelljs/issues/44) -- Executing SSH with ShellJs [\#43](https://github.com/shelljs/shelljs/issues/43) - -**Merged pull requests:** - -- Fix for \#44 [\#46](https://github.com/shelljs/shelljs/pull/46) ([mstade](https://github.com/mstade)) -- Fix single/double quotes in exec [\#42](https://github.com/shelljs/shelljs/pull/42) ([danielepolencic](https://github.com/danielepolencic)) - -## [v0.0.9](https://github.com/shelljs/shelljs/tree/v0.0.9) (2012-12-01) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.8...v0.0.9) - -**Closed issues:** - -- silent output [\#40](https://github.com/shelljs/shelljs/issues/40) -- asynchronous exec [\#34](https://github.com/shelljs/shelljs/issues/34) - -**Merged pull requests:** - -- Passed process arguments to executable script [\#36](https://github.com/shelljs/shelljs/pull/36) ([Zanisimo](https://github.com/Zanisimo)) - -## [v0.0.8](https://github.com/shelljs/shelljs/tree/v0.0.8) (2012-10-11) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.7...v0.0.8) - -**Closed issues:** - -- 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) - -**Merged pull requests:** - -- fix: global leak 'stats' [\#29](https://github.com/shelljs/shelljs/pull/29) ([ando-takahiro](https://github.com/ando-takahiro)) -- -a includes . and ..; -A does not [\#28](https://github.com/shelljs/shelljs/pull/28) ([aeosynth](https://github.com/aeosynth)) - -## [v0.0.7](https://github.com/shelljs/shelljs/tree/v0.0.7) (2012-09-23) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.6...v0.0.7) - -**Closed issues:** - -- 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:** - -- add primaries to \_test [\#23](https://github.com/shelljs/shelljs/pull/23) ([aeosynth](https://github.com/aeosynth)) - -## [v0.0.6](https://github.com/shelljs/shelljs/tree/v0.0.6) (2012-08-07) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.6pre2...v0.0.6) - -**Merged pull requests:** - -- Fixed a global variable leak [\#16](https://github.com/shelljs/shelljs/pull/16) ([dallonf](https://github.com/dallonf)) - -## [v0.0.6pre2](https://github.com/shelljs/shelljs/tree/v0.0.6pre2) (2012-05-25) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.6pre1...v0.0.6pre2) - -## [v0.0.6pre1](https://github.com/shelljs/shelljs/tree/v0.0.6pre1) (2012-05-25) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5...v0.0.6pre1) - -## [v0.0.5](https://github.com/shelljs/shelljs/tree/v0.0.5) (2012-05-24) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5pre4...v0.0.5) - -**Closed issues:** - -- global.key assigned value 'async' as a result of shell.exec\(...\) [\#12](https://github.com/shelljs/shelljs/issues/12) - -**Merged pull requests:** - -- Add support for grep option -v. [\#13](https://github.com/shelljs/shelljs/pull/13) ([kkujala](https://github.com/kkujala)) - -## [v0.0.5pre4](https://github.com/shelljs/shelljs/tree/v0.0.5pre4) (2012-03-27) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5pre3...v0.0.5pre4) - -## [v0.0.5pre3](https://github.com/shelljs/shelljs/tree/v0.0.5pre3) (2012-03-27) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5pre2...v0.0.5pre3) - -## [v0.0.5pre2](https://github.com/shelljs/shelljs/tree/v0.0.5pre2) (2012-03-26) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5pre1...v0.0.5pre2) - -## [v0.0.5pre1](https://github.com/shelljs/shelljs/tree/v0.0.5pre1) (2012-03-26) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.4...v0.0.5pre1) - -**Closed issues:** - -- rm\(\) does not respect read/write modes [\#6](https://github.com/shelljs/shelljs/issues/6) - -## [v0.0.4](https://github.com/shelljs/shelljs/tree/v0.0.4) (2012-03-22) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.3...v0.0.4) - -**Closed issues:** - -- "For convenient iteration via `for in`, ..."? [\#4](https://github.com/shelljs/shelljs/issues/4) - -## [v0.0.3](https://github.com/shelljs/shelljs/tree/v0.0.3) (2012-03-21) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.2...v0.0.3) - -## [v0.0.2](https://github.com/shelljs/shelljs/tree/v0.0.2) (2012-03-15) -[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.2pre1...v0.0.2) - -## [v0.0.2pre1](https://github.com/shelljs/shelljs/tree/v0.0.2pre1) (2012-03-03) - - -\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file +There is no job for shelljs/shelljs. Make a POST first. \ No newline at end of file From 0ff1244a7e36d8c7961024b670cc79596a101773 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Sun, 8 Jan 2017 14:39:40 -0800 Subject: [PATCH 002/108] docs(changelog): updated by Brandon Freitag [ci skip] --- CHANGELOG.md | 709 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 708 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8d7ab214..e66d72cf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,708 @@ -There is no job for shelljs/shelljs. Make a POST first. \ No newline at end of file +# Change Log + +## [v0.7.6](https://github.com/shelljs/shelljs/tree/v0.7.6) (2017-01-08) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.5...v0.7.6) + +**Closed issues:** + +- unable to execute ionic command with shell js [\#640](https://github.com/shelljs/shelljs/issues/640) +- How to increase ShellJS buffer size? [\#639](https://github.com/shelljs/shelljs/issues/639) +- mkdir fails with non-normalized path [\#634](https://github.com/shelljs/shelljs/issues/634) +- Move execPath into common [\#633](https://github.com/shelljs/shelljs/issues/633) +- QUESTION: Feedback while an operation is running? [\#629](https://github.com/shelljs/shelljs/issues/629) +- Test setup/cleanup is broken [\#621](https://github.com/shelljs/shelljs/issues/621) +- Ignore temp directories when running lint [\#620](https://github.com/shelljs/shelljs/issues/620) +- parseOptions should throw an error if the option string doesn't start with '-' [\#614](https://github.com/shelljs/shelljs/issues/614) +- chore: LGTM.co is gone [\#595](https://github.com/shelljs/shelljs/issues/595) +- refactor: objectAssign should refer to Object.assign if it exists, or the internal polyfill otherwise [\#592](https://github.com/shelljs/shelljs/issues/592) +- parseOptions: allow a way to keep errors silent \(exception only\) [\#591](https://github.com/shelljs/shelljs/issues/591) +- \[Question\] commands with multiple options / arguments? [\#589](https://github.com/shelljs/shelljs/issues/589) +- feature: GNU Parallel [\#585](https://github.com/shelljs/shelljs/issues/585) +- 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) +- 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) +- 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) +- Add a way to prevent shell-expansion on commands \(this issue is not for exec\) [\#345](https://github.com/shelljs/shelljs/issues/345) +- Chown [\#183](https://github.com/shelljs/shelljs/issues/183) +- spawn EMFILE [\#81](https://github.com/shelljs/shelljs/issues/81) +- Rewrite exec using execsync-ng \(which uses node-ffi\) [\#66](https://github.com/shelljs/shelljs/issues/66) +- `exec` gets stuck on my Debian box [\#51](https://github.com/shelljs/shelljs/issues/51) +- 100% cpu usage when a nodejs script goes side ways executing a command. [\#5](https://github.com/shelljs/shelljs/issues/5) + +**Merged pull requests:** + +- refactor: add config.reset\(\) and .resetForTesting\(\) [\#641](https://github.com/shelljs/shelljs/pull/641) ([nfischer](https://github.com/nfischer)) +- chore: set up test coverage [\#638](https://github.com/shelljs/shelljs/pull/638) ([nfischer](https://github.com/nfischer)) +- refactor: create common.execPath [\#636](https://github.com/shelljs/shelljs/pull/636) ([nfischer](https://github.com/nfischer)) +- fix: allow non-normalized paths as input to mkdir [\#635](https://github.com/shelljs/shelljs/pull/635) ([nfischer](https://github.com/nfischer)) +- Finalize moving to ava [\#630](https://github.com/shelljs/shelljs/pull/630) ([freitagbr](https://github.com/freitagbr)) +- test: refactor pushd tests to AVA [\#627](https://github.com/shelljs/shelljs/pull/627) ([nfischer](https://github.com/nfischer)) +- test: refactor popd tests to AVA [\#626](https://github.com/shelljs/shelljs/pull/626) ([nfischer](https://github.com/nfischer)) +- test: refactor shjs tests to AVA [\#625](https://github.com/shelljs/shelljs/pull/625) ([nfischer](https://github.com/nfischer)) +- test: remove tests for make \(deprecated\) [\#624](https://github.com/shelljs/shelljs/pull/624) ([nfischer](https://github.com/nfischer)) +- Ignore test temp directories during linting [\#623](https://github.com/shelljs/shelljs/pull/623) ([freitagbr](https://github.com/freitagbr)) +- refactor: list all commands in commands.json [\#616](https://github.com/shelljs/shelljs/pull/616) ([nfischer](https://github.com/nfischer)) +- Throw an error if the options string does not start with '-' [\#615](https://github.com/shelljs/shelljs/pull/615) ([freitagbr](https://github.com/freitagbr)) +- chore: switch to files attribute from npmignore [\#613](https://github.com/shelljs/shelljs/pull/613) ([nfischer](https://github.com/nfischer)) +- test: refactor 'test' command tests to AVA [\#612](https://github.com/shelljs/shelljs/pull/612) ([nfischer](https://github.com/nfischer)) +- test: refactor find tests to AVA [\#611](https://github.com/shelljs/shelljs/pull/611) ([nfischer](https://github.com/nfischer)) +- test: refactor ln tests to AVA [\#610](https://github.com/shelljs/shelljs/pull/610) ([nfischer](https://github.com/nfischer)) +- test: refactor ls to use AVA [\#609](https://github.com/shelljs/shelljs/pull/609) ([nfischer](https://github.com/nfischer)) +- test: refactor pipe tests to AVA [\#608](https://github.com/shelljs/shelljs/pull/608) ([nfischer](https://github.com/nfischer)) +- test: refactor sed tests to AVA [\#607](https://github.com/shelljs/shelljs/pull/607) ([nfischer](https://github.com/nfischer)) +- test: refactor grep tests to AVA [\#606](https://github.com/shelljs/shelljs/pull/606) ([nfischer](https://github.com/nfischer)) +- test: refactor global tests to AVA [\#605](https://github.com/shelljs/shelljs/pull/605) ([nfischer](https://github.com/nfischer)) +- test: refactor touch tests to AVA [\#604](https://github.com/shelljs/shelljs/pull/604) ([nfischer](https://github.com/nfischer)) +- test: refactor uniq tests to AVA [\#603](https://github.com/shelljs/shelljs/pull/603) ([nfischer](https://github.com/nfischer)) +- test: refactor sort tests to AVA [\#602](https://github.com/shelljs/shelljs/pull/602) ([nfischer](https://github.com/nfischer)) +- test: refactor tail tests to AVA [\#601](https://github.com/shelljs/shelljs/pull/601) ([nfischer](https://github.com/nfischer)) +- test: refactor head tests to AVA [\#600](https://github.com/shelljs/shelljs/pull/600) ([nfischer](https://github.com/nfischer)) +- test: refactor mkdir tests to AVA [\#599](https://github.com/shelljs/shelljs/pull/599) ([nfischer](https://github.com/nfischer)) +- Fix: rm behavior regarding symlinks [\#598](https://github.com/shelljs/shelljs/pull/598) ([freitagbr](https://github.com/freitagbr)) +- test: refactor mv tests to AVA [\#597](https://github.com/shelljs/shelljs/pull/597) ([nfischer](https://github.com/nfischer)) +- Remove files related to lgtm.co [\#596](https://github.com/shelljs/shelljs/pull/596) ([freitagbr](https://github.com/freitagbr)) +- Add ability to configure error from parseOptions [\#594](https://github.com/shelljs/shelljs/pull/594) ([freitagbr](https://github.com/freitagbr)) +- Use Object.assign if possible [\#593](https://github.com/shelljs/shelljs/pull/593) ([freitagbr](https://github.com/freitagbr)) +- Add "-n" option to echo [\#590](https://github.com/shelljs/shelljs/pull/590) ([freitagbr](https://github.com/freitagbr)) +- test: refactor rm tests to AVA [\#586](https://github.com/shelljs/shelljs/pull/586) ([nfischer](https://github.com/nfischer)) +- test: refactor pwd tests to AVA [\#582](https://github.com/shelljs/shelljs/pull/582) ([nfischer](https://github.com/nfischer)) +- test: refactor tempdir tests to AVA [\#581](https://github.com/shelljs/shelljs/pull/581) ([nfischer](https://github.com/nfischer)) +- test: refactor 'which' tests to AVA [\#580](https://github.com/shelljs/shelljs/pull/580) ([nfischer](https://github.com/nfischer)) +- test: refactor plugin tests to AVA [\#579](https://github.com/shelljs/shelljs/pull/579) ([nfischer](https://github.com/nfischer)) +- test: refactor toEnd tests to AVA [\#578](https://github.com/shelljs/shelljs/pull/578) ([nfischer](https://github.com/nfischer)) +- test: refactor to tests to AVA [\#577](https://github.com/shelljs/shelljs/pull/577) ([nfischer](https://github.com/nfischer)) +- test: refactor 'set' tests to AVA [\#576](https://github.com/shelljs/shelljs/pull/576) ([nfischer](https://github.com/nfischer)) +- test: refactor echo tests to AVA [\#575](https://github.com/shelljs/shelljs/pull/575) ([nfischer](https://github.com/nfischer)) +- test: refactor exec tests to AVA [\#574](https://github.com/shelljs/shelljs/pull/574) ([nfischer](https://github.com/nfischer)) +- test: refactor env tests to AVA [\#573](https://github.com/shelljs/shelljs/pull/573) ([nfischer](https://github.com/nfischer)) +- test: refactor dirs tests to AVA [\#572](https://github.com/shelljs/shelljs/pull/572) ([nfischer](https://github.com/nfischer)) +- test: refactor config tests to AVA [\#571](https://github.com/shelljs/shelljs/pull/571) ([nfischer](https://github.com/nfischer)) +- test: refactor common tests to AVA [\#570](https://github.com/shelljs/shelljs/pull/570) ([nfischer](https://github.com/nfischer)) +- test: refactor chmod tests to AVA [\#569](https://github.com/shelljs/shelljs/pull/569) ([nfischer](https://github.com/nfischer)) +- test: refactor cp tests to ava [\#565](https://github.com/shelljs/shelljs/pull/565) ([nfischer](https://github.com/nfischer)) +- test: refactor cat tests to ava [\#564](https://github.com/shelljs/shelljs/pull/564) ([nfischer](https://github.com/nfischer)) +- test: set up ava and move cd.js [\#561](https://github.com/shelljs/shelljs/pull/561) ([nfischer](https://github.com/nfischer)) +- Update sed documentation regarding capture groups [\#558](https://github.com/shelljs/shelljs/pull/558) ([freitagbr](https://github.com/freitagbr)) +- Add newline to output of echo [\#557](https://github.com/shelljs/shelljs/pull/557) ([freitagbr](https://github.com/freitagbr)) +- fix: handle code-less errors more carefully in exec [\#554](https://github.com/shelljs/shelljs/pull/554) ([nfischer](https://github.com/nfischer)) +- 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)) + +## [v0.7.5](https://github.com/shelljs/shelljs/tree/v0.7.5) (2016-10-27) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.4...v0.7.5) + +**Closed issues:** + +- Project objectives: there is some higher goal to achieve? [\#533](https://github.com/shelljs/shelljs/issues/533) +- fs.existsSync is un-deprecated [\#531](https://github.com/shelljs/shelljs/issues/531) +- Inadvertent breaking change to shell.test\(\) [\#529](https://github.com/shelljs/shelljs/issues/529) +- Add -u flag support for cp [\#526](https://github.com/shelljs/shelljs/issues/526) +- API request: allow `plugin.error\(\)` to take an options parameter [\#522](https://github.com/shelljs/shelljs/issues/522) +- FS Real Path error thrown when requiring shelljs [\#521](https://github.com/shelljs/shelljs/issues/521) +- Question: passing code via pipe? [\#520](https://github.com/shelljs/shelljs/issues/520) +- The performance in `cp` is different between `0.6.0` and `0.7.4` [\#517](https://github.com/shelljs/shelljs/issues/517) +- 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:** + +- feat: plugin.error\(\) takes an options parameter [\#535](https://github.com/shelljs/shelljs/pull/535) ([nfischer](https://github.com/nfischer)) +- Revert "refactor: replace fs.existsSync" fixes\(\#531\) [\#532](https://github.com/shelljs/shelljs/pull/532) ([gyandeeps](https://github.com/gyandeeps)) +- Fix: Remove default glob from shell.test \(fixes \#529\) [\#530](https://github.com/shelljs/shelljs/pull/530) ([gyandeeps](https://github.com/gyandeeps)) +- feat: cp -u option [\#527](https://github.com/shelljs/shelljs/pull/527) ([nfischer](https://github.com/nfischer)) +- chore: add downloads per month on README [\#513](https://github.com/shelljs/shelljs/pull/513) ([nfischer](https://github.com/nfischer)) + +## [v0.7.4](https://github.com/shelljs/shelljs/tree/v0.7.4) (2016-08-26) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.3...v0.7.4) + +**Closed issues:** + +- fix: echo -e should not print "-e" [\#510](https://github.com/shelljs/shelljs/issues/510) +- Wrong method signature in doc [\#498](https://github.com/shelljs/shelljs/issues/498) +- readFromPipe should be a function with no arguments [\#485](https://github.com/shelljs/shelljs/issues/485) +- TypeError: Cannot read property 'toString' of undefined [\#471](https://github.com/shelljs/shelljs/issues/471) + +**Merged pull requests:** + +- fix: echo supports -e option properly [\#511](https://github.com/shelljs/shelljs/pull/511) ([nfischer](https://github.com/nfischer)) +- refactor: replace fs.existsSync [\#509](https://github.com/shelljs/shelljs/pull/509) ([nfischer](https://github.com/nfischer)) +- refactor: readFromPipe\(\) requires no arguments [\#506](https://github.com/shelljs/shelljs/pull/506) ([nfischer](https://github.com/nfischer)) +- chore: switch to eslint [\#504](https://github.com/shelljs/shelljs/pull/504) ([nfischer](https://github.com/nfischer)) +- feat: add overWrite option for commands [\#503](https://github.com/shelljs/shelljs/pull/503) ([nfischer](https://github.com/nfischer)) +- chore: update issue template [\#502](https://github.com/shelljs/shelljs/pull/502) ([nfischer](https://github.com/nfischer)) +- fixed head/tail readme [\#499](https://github.com/shelljs/shelljs/pull/499) ([charlesread](https://github.com/charlesread)) + +## [v0.7.3](https://github.com/shelljs/shelljs/tree/v0.7.3) (2016-07-27) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.2...v0.7.3) + +**Closed issues:** + +- expose execSync [\#494](https://github.com/shelljs/shelljs/issues/494) +- Add a way to create commands that can receive from a pipe without being standalone commands [\#487](https://github.com/shelljs/shelljs/issues/487) +- cp -r breaks when the directory contains a softlink [\#193](https://github.com/shelljs/shelljs/issues/193) +- Redirect output to file fails [\#60](https://github.com/shelljs/shelljs/issues/60) +- We need sed -n ? [\#38](https://github.com/shelljs/shelljs/issues/38) + +**Merged pull requests:** + +- refactor: allow pipeOnly commands \(methods on ShellStrings\) [\#493](https://github.com/shelljs/shelljs/pull/493) ([nfischer](https://github.com/nfischer)) +- refactor: glob by default for commands [\#492](https://github.com/shelljs/shelljs/pull/492) ([nfischer](https://github.com/nfischer)) +- refactor: switch from notUnix to unix in wrap\(\) [\#491](https://github.com/shelljs/shelljs/pull/491) ([nfischer](https://github.com/nfischer)) +- refactor: switch common.extend\(\) to Object.assign ponyfill [\#490](https://github.com/shelljs/shelljs/pull/490) ([nfischer](https://github.com/nfischer)) +- fix: conflicting options now properly override each other [\#489](https://github.com/shelljs/shelljs/pull/489) ([nfischer](https://github.com/nfischer)) +- refactor: expose plugin utils & add initial tests [\#484](https://github.com/shelljs/shelljs/pull/484) ([nfischer](https://github.com/nfischer)) + +## [v0.7.2](https://github.com/shelljs/shelljs/tree/v0.7.2) (2016-07-25) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.1...v0.7.2) + +**Closed issues:** + +- shelljs should not kill process if node call throws exception [\#473](https://github.com/shelljs/shelljs/issues/473) +- `cp` work incorrectly when folder name contains '@' [\#463](https://github.com/shelljs/shelljs/issues/463) +- Something went wrong [\#158](https://github.com/shelljs/shelljs/issues/158) + +**Merged pull requests:** + +- fix: resolve a cylcic-dependency problem [\#482](https://github.com/shelljs/shelljs/pull/482) ([nfischer](https://github.com/nfischer)) +- refactor: add wrapOutput option to auto-ShellString-ify command output [\#481](https://github.com/shelljs/shelljs/pull/481) ([nfischer](https://github.com/nfischer)) +- refactor: move option parsing into common.wrap\(\) [\#479](https://github.com/shelljs/shelljs/pull/479) ([nfischer](https://github.com/nfischer)) +- refactor: hook new uniq\(\) command using new format [\#478](https://github.com/shelljs/shelljs/pull/478) ([nfischer](https://github.com/nfischer)) +- Fix mkdir malformed path [\#477](https://github.com/shelljs/shelljs/pull/477) ([nfischer](https://github.com/nfischer)) +- fix: mkdir for invalid perms does not kill process [\#474](https://github.com/shelljs/shelljs/pull/474) ([nfischer](https://github.com/nfischer)) +- feat\(command\): new command: uniq\(\) [\#453](https://github.com/shelljs/shelljs/pull/453) ([joshi-sh](https://github.com/joshi-sh)) + +## [v0.7.1](https://github.com/shelljs/shelljs/tree/v0.7.1) (2016-07-22) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.0...v0.7.1) + +**Closed issues:** + +- cp -n doesn't work correctly [\#465](https://github.com/shelljs/shelljs/issues/465) +- how can i run sudo apt-get install xtodotool by your plugin? [\#448](https://github.com/shelljs/shelljs/issues/448) +- shell.js grep: internal error, Invalid regular expression [\#447](https://github.com/shelljs/shelljs/issues/447) +- 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:** + +- refactor: commands now register themselves [\#475](https://github.com/shelljs/shelljs/pull/475) ([nfischer](https://github.com/nfischer)) +- chore: switch to shields.io, and add npm badge [\#470](https://github.com/shelljs/shelljs/pull/470) ([nfischer](https://github.com/nfischer)) +- fix\(cp\): -n option no longer raises error [\#466](https://github.com/shelljs/shelljs/pull/466) ([nfischer](https://github.com/nfischer)) +- refactor: expose pipe-ability to command configuration [\#464](https://github.com/shelljs/shelljs/pull/464) ([nfischer](https://github.com/nfischer)) +- fix\(mv\): works across partitions [\#461](https://github.com/shelljs/shelljs/pull/461) ([nfischer](https://github.com/nfischer)) +- chore: switch to shelljs-changelog [\#460](https://github.com/shelljs/shelljs/pull/460) ([nfischer](https://github.com/nfischer)) +- chore: update release process [\#459](https://github.com/shelljs/shelljs/pull/459) ([nfischer](https://github.com/nfischer)) +- chore: revert depreciate shelljs/make \(\#431\) [\#458](https://github.com/shelljs/shelljs/pull/458) ([zephraph](https://github.com/zephraph)) +- chore: clarify message for when docs are not generated [\#457](https://github.com/shelljs/shelljs/pull/457) ([nfischer](https://github.com/nfischer)) +- chore\(gendocs\): add `npm run gendocs` command [\#455](https://github.com/shelljs/shelljs/pull/455) ([nfischer](https://github.com/nfischer)) +- chore: update jshint and move it to an npm script [\#454](https://github.com/shelljs/shelljs/pull/454) ([nfischer](https://github.com/nfischer)) +- test\(ls\): add case for trailing slash on dir name [\#450](https://github.com/shelljs/shelljs/pull/450) ([nfischer](https://github.com/nfischer)) +- docs\(exec\): explicitly mention the `shell` option [\#449](https://github.com/shelljs/shelljs/pull/449) ([nfischer](https://github.com/nfischer)) +- chore: setup changelog [\#443](https://github.com/shelljs/shelljs/pull/443) ([levithomason](https://github.com/levithomason)) +- 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) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.6.0...v0.7.0) + +**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) +- Refactor more commands to return ShellString [\#373](https://github.com/shelljs/shelljs/issues/373) +- ln\('-sf', './', '\'\) is not linking the right folder [\#363](https://github.com/shelljs/shelljs/issues/363) +- v0.6.0 - shell.cp\('r', '/foo/\*, '/bar'\) fails with /foo/\* no such file or directory [\#342](https://github.com/shelljs/shelljs/issues/342) +- Add documentup as a webhook [\#327](https://github.com/shelljs/shelljs/issues/327) +- Dir glob breaks when in the middle of path [\#245](https://github.com/shelljs/shelljs/issues/245) +- could you switch off wiki page? [\#233](https://github.com/shelljs/shelljs/issues/233) +- ls globbing does not behave like shell, consider using glob.sync [\#225](https://github.com/shelljs/shelljs/issues/225) +- Cannot run shell.exec\('heroku config:push'\) -- just hangs [\#218](https://github.com/shelljs/shelljs/issues/218) +- `cp` does not overwrite files by default [\#210](https://github.com/shelljs/shelljs/issues/210) +- exec failed to return [\#208](https://github.com/shelljs/shelljs/issues/208) +- CLI Version [\#202](https://github.com/shelljs/shelljs/issues/202) +- Bracket expansion not working [\#176](https://github.com/shelljs/shelljs/issues/176) +- "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) +- Only get stdout from `exec` [\#92](https://github.com/shelljs/shelljs/issues/92) +- What about other commands? [\#90](https://github.com/shelljs/shelljs/issues/90) +- Flesh out example of exit\(\) [\#73](https://github.com/shelljs/shelljs/issues/73) +- exec doesn't work with qualified paths on windows [\#41](https://github.com/shelljs/shelljs/issues/41) +- exec does not working in mingw bash in windows [\#17](https://github.com/shelljs/shelljs/issues/17) +- Add support for cp -P option [\#413](https://github.com/shelljs/shelljs/issues/413) +- cp -L: Incorrect behavior for symlinks to regular files [\#407](https://github.com/shelljs/shelljs/issues/407) +- Edit the docs to emphasize ShellStrings and Pipes [\#398](https://github.com/shelljs/shelljs/issues/398) +- Error message isn't always printed [\#372](https://github.com/shelljs/shelljs/issues/372) +- Standardize command output [\#356](https://github.com/shelljs/shelljs/issues/356) +- exec\(\) doesn't clean up all temp files [\#353](https://github.com/shelljs/shelljs/issues/353) +- Document that exec\(\) options don't work on early versions of node [\#350](https://github.com/shelljs/shelljs/issues/350) +- Add -f option to set\(\) [\#344](https://github.com/shelljs/shelljs/issues/344) +- Glob commands by default [\#343](https://github.com/shelljs/shelljs/issues/343) +- rm -rf incorrect behaviour [\#332](https://github.com/shelljs/shelljs/issues/332) +- Switch `exec\(\)` to use bash by default [\#281](https://github.com/shelljs/shelljs/issues/281) +- pipe to proc [\#148](https://github.com/shelljs/shelljs/issues/148) +- shell builtin [\#138](https://github.com/shelljs/shelljs/issues/138) +- add timeout option for exec [\#132](https://github.com/shelljs/shelljs/issues/132) +- shelljs cp handling symlinks badly [\#69](https://github.com/shelljs/shelljs/issues/69) + +**Merged pull requests:** + +- chore: add "Team" section to README [\#423](https://github.com/shelljs/shelljs/pull/423) ([nfischer](https://github.com/nfischer)) +- Contributing guidelines [\#422](https://github.com/shelljs/shelljs/pull/422) ([nfischer](https://github.com/nfischer)) +- feat\(glob\): expose config.globOptions. [\#400](https://github.com/shelljs/shelljs/pull/400) ([nfischer](https://github.com/nfischer)) +- Add shelljs as a keyword in package.json [\#393](https://github.com/shelljs/shelljs/pull/393) ([nfischer](https://github.com/nfischer)) +- docs: add link to wiki page [\#392](https://github.com/shelljs/shelljs/pull/392) ([nfischer](https://github.com/nfischer)) +- refactor\(cd\): use process.env.OLDPWD to store previous dir [\#383](https://github.com/shelljs/shelljs/pull/383) ([nfischer](https://github.com/nfischer)) +- chore\(appveyor\): add in node 4 for appveyor [\#381](https://github.com/shelljs/shelljs/pull/381) ([nfischer](https://github.com/nfischer)) +- Add Cash cross-reference [\#375](https://github.com/shelljs/shelljs/pull/375) ([dthree](https://github.com/dthree)) +- Ignore gitattributes from npm package [\#361](https://github.com/shelljs/shelljs/pull/361) ([nfischer](https://github.com/nfischer)) +- Consistently use LF line endings [\#355](https://github.com/shelljs/shelljs/pull/355) ([TimothyGu](https://github.com/TimothyGu)) +- Release v0.7.0 [\#429](https://github.com/shelljs/shelljs/pull/429) ([nfischer](https://github.com/nfischer)) +- fix: null is no longer confused for an object [\#428](https://github.com/shelljs/shelljs/pull/428) ([nfischer](https://github.com/nfischer)) +- fix\(ls\): no trailing newline for empty directories [\#425](https://github.com/shelljs/shelljs/pull/425) ([nfischer](https://github.com/nfischer)) +- feat\(cp\): -P option, plus better handling of symlinks [\#421](https://github.com/shelljs/shelljs/pull/421) ([nfischer](https://github.com/nfischer)) +- docs\(exec\): fix docs about exec return type [\#419](https://github.com/shelljs/shelljs/pull/419) ([nfischer](https://github.com/nfischer)) +- docs\(error\): deprecate relying on string value [\#418](https://github.com/shelljs/shelljs/pull/418) ([nfischer](https://github.com/nfischer)) +- fix: error message now printed for fatal failures [\#417](https://github.com/shelljs/shelljs/pull/417) ([nfischer](https://github.com/nfischer)) +- issue-407: Add regular files unit tests and fix symlink copy behavior [\#409](https://github.com/shelljs/shelljs/pull/409) ([charlesverge](https://github.com/charlesverge)) +- refactor\(rm\): Remove duplicate code [\#408](https://github.com/shelljs/shelljs/pull/408) ([nfischer](https://github.com/nfischer)) +- docs: wildcards for all commands, other docs cleanups [\#404](https://github.com/shelljs/shelljs/pull/404) ([nfischer](https://github.com/nfischer)) +- test\(rm\): add tests to prevent a future regression [\#403](https://github.com/shelljs/shelljs/pull/403) ([nfischer](https://github.com/nfischer)) +- refactor\(string\): modify string protoype, but only for shelljs/global [\#401](https://github.com/shelljs/shelljs/pull/401) ([nfischer](https://github.com/nfischer)) +- feat: adding error codes to ShellJS [\#394](https://github.com/shelljs/shelljs/pull/394) ([nfischer](https://github.com/nfischer)) +- feature: use rechoir [\#384](https://github.com/shelljs/shelljs/pull/384) ([nfischer](https://github.com/nfischer)) +- refactor\(cp\): clean up code and fix \#376 [\#380](https://github.com/shelljs/shelljs/pull/380) ([nfischer](https://github.com/nfischer)) +- New commands: sort\(\), head\(\), and tail\(\) [\#379](https://github.com/shelljs/shelljs/pull/379) ([nfischer](https://github.com/nfischer)) +- Add unit tests to prevent regression \(see \#376\) [\#378](https://github.com/shelljs/shelljs/pull/378) ([nfischer](https://github.com/nfischer)) +- feat\(pipe\): add support for pipes between commands [\#370](https://github.com/shelljs/shelljs/pull/370) ([nfischer](https://github.com/nfischer)) +- refactor\(ls\): greatly simplify ls implimentation [\#369](https://github.com/shelljs/shelljs/pull/369) ([ariporad](https://github.com/ariporad)) +- chore: drop node v0.10 support [\#368](https://github.com/shelljs/shelljs/pull/368) ([ariporad](https://github.com/ariporad)) +- perf\(cd\): only run `stat` once [\#367](https://github.com/shelljs/shelljs/pull/367) ([ariporad](https://github.com/ariporad)) +- fix\(exec\): properly handles paths with spaces and quotes [\#365](https://github.com/shelljs/shelljs/pull/365) ([nfischer](https://github.com/nfischer)) +- test\(ln\): add tests for linking to cwd [\#364](https://github.com/shelljs/shelljs/pull/364) ([nfischer](https://github.com/nfischer)) +- fix\(verbose\): verbose-style logging is consistent [\#362](https://github.com/shelljs/shelljs/pull/362) ([nfischer](https://github.com/nfischer)) +- Refactor shellstring [\#360](https://github.com/shelljs/shelljs/pull/360) ([nfischer](https://github.com/nfischer)) +- feat\(glob\): use glob module for globbing [\#359](https://github.com/shelljs/shelljs/pull/359) ([nfischer](https://github.com/nfischer)) +- feat\(set\): add -f option to disable globbing [\#358](https://github.com/shelljs/shelljs/pull/358) ([nfischer](https://github.com/nfischer)) +- config.fatal now throws an exception [\#357](https://github.com/shelljs/shelljs/pull/357) ([jrmclaurin](https://github.com/jrmclaurin)) +- fix\(exec\): temp files are now cleaned up [\#354](https://github.com/shelljs/shelljs/pull/354) ([nfischer](https://github.com/nfischer)) +- feat\(glob\): glob support for \(almost\) all commands [\#352](https://github.com/shelljs/shelljs/pull/352) ([nfischer](https://github.com/nfischer)) +- feat\(grep\): add -l option [\#349](https://github.com/shelljs/shelljs/pull/349) ([nfischer](https://github.com/nfischer)) +- fix\(exec\): now actually supports shell option [\#348](https://github.com/shelljs/shelljs/pull/348) ([nfischer](https://github.com/nfischer)) +- feat\(touch\): supports multiple files [\#346](https://github.com/shelljs/shelljs/pull/346) ([nfischer](https://github.com/nfischer)) + +## [v0.6.0](https://github.com/shelljs/shelljs/tree/v0.6.0) (2016-02-05) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.5.3...v0.6.0) + +**Closed issues:** + +- option not recognized [\#334](https://github.com/shelljs/shelljs/issues/334) +- Feature request: Metadata with `ls` [\#323](https://github.com/shelljs/shelljs/issues/323) +- Gen-docs is broken [\#309](https://github.com/shelljs/shelljs/issues/309) +- `link -s` is broken for files on Windows [\#301](https://github.com/shelljs/shelljs/issues/301) +- Shelljs quits unexpectedly: [\#300](https://github.com/shelljs/shelljs/issues/300) +- Failing tests on Windows [\#296](https://github.com/shelljs/shelljs/issues/296) +- run-tests.js is broken for cmd.exe [\#294](https://github.com/shelljs/shelljs/issues/294) +- Support echo-ing environment variables [\#291](https://github.com/shelljs/shelljs/issues/291) +- Add Windows CI [\#287](https://github.com/shelljs/shelljs/issues/287) +- Add tests for the shjs utility [\#280](https://github.com/shelljs/shelljs/issues/280) +- Allow shjs utility to infer the extension for "filename." [\#278](https://github.com/shelljs/shelljs/issues/278) +- Ability to read the stdout buffer line-by-line [\#277](https://github.com/shelljs/shelljs/issues/277) +- Poor output for commands with multiple errors [\#267](https://github.com/shelljs/shelljs/issues/267) +- Travis ci build status says "unknown" [\#266](https://github.com/shelljs/shelljs/issues/266) +- wild card characters in filename not working as expected [\#262](https://github.com/shelljs/shelljs/issues/262) +- shell.exec - read internal variable [\#260](https://github.com/shelljs/shelljs/issues/260) +- cp and rename directory with -r doesn't match unix behavior [\#256](https://github.com/shelljs/shelljs/issues/256) +- console.log.apply throwing TypeError: Illegal Invocation [\#255](https://github.com/shelljs/shelljs/issues/255) +- How to exit on first error [\#253](https://github.com/shelljs/shelljs/issues/253) +- why not support set 'cwd' when invoke execAsync ? [\#250](https://github.com/shelljs/shelljs/issues/250) +- Not possible to check the failure of cd? [\#247](https://github.com/shelljs/shelljs/issues/247) +- By default shelljs runs command in root [\#246](https://github.com/shelljs/shelljs/issues/246) +- /usr/bin/env: node: No such file or directory [\#243](https://github.com/shelljs/shelljs/issues/243) +- "Which" command not working properly on Windows Platform. [\#238](https://github.com/shelljs/shelljs/issues/238) +- Arguments [\#237](https://github.com/shelljs/shelljs/issues/237) +- 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) +- boolean return value for string.to\(\) [\#205](https://github.com/shelljs/shelljs/issues/205) +- `common.error` doesn't throw [\#199](https://github.com/shelljs/shelljs/issues/199) +- Problems with exec \(sync\) on 0.12/io.js [\#197](https://github.com/shelljs/shelljs/issues/197) +- cp --update flag [\#172](https://github.com/shelljs/shelljs/issues/172) +- Is there a way to suppress pushd/popd output? [\#171](https://github.com/shelljs/shelljs/issues/171) +- 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) +- Error ENOTEMPTY when deleting a directory recursively. [\#49](https://github.com/shelljs/shelljs/issues/49) +- Cross-platform way to add to PATH [\#32](https://github.com/shelljs/shelljs/issues/32) +- `mv` fails on block, character, fifo [\#25](https://github.com/shelljs/shelljs/issues/25) +- ls -l [\#22](https://github.com/shelljs/shelljs/issues/22) + +**Merged pull requests:** + +- feat\(set\): add new set\(\) command [\#329](https://github.com/shelljs/shelljs/pull/329) ([nfischer](https://github.com/nfischer)) +- Fix symlinking on Windows [\#322](https://github.com/shelljs/shelljs/pull/322) ([BYK](https://github.com/BYK)) +- Rewrite .gitignore to be more comprehensive [\#321](https://github.com/shelljs/shelljs/pull/321) ([BYK](https://github.com/BYK)) +- chore\(gitter/travis\): add gitter webhook to travis [\#313](https://github.com/shelljs/shelljs/pull/313) ([ariporad](https://github.com/ariporad)) +- chore\(LGTM\): add LGTM config files [\#312](https://github.com/shelljs/shelljs/pull/312) ([ariporad](https://github.com/ariporad)) +- feat\(ls\): add -d flag to ls\(\) [\#311](https://github.com/shelljs/shelljs/pull/311) ([nfischer](https://github.com/nfischer)) +- fix\(gen-docs\): fix issue where docs are generated wrong [\#310](https://github.com/shelljs/shelljs/pull/310) ([nfischer](https://github.com/nfischer)) +- chore\(package\): remove v0.8 from engines list [\#308](https://github.com/shelljs/shelljs/pull/308) ([nfischer](https://github.com/nfischer)) +- travis: Mark as not using `sudo` and do not test 0.11 [\#307](https://github.com/shelljs/shelljs/pull/307) ([TimothyGu](https://github.com/TimothyGu)) +- fix: jshint works on Windows [\#295](https://github.com/shelljs/shelljs/pull/295) ([nfischer](https://github.com/nfischer)) +- feat: add tilde expansion to expand\(\) [\#293](https://github.com/shelljs/shelljs/pull/293) ([nfischer](https://github.com/nfischer)) +- style: make docs more consistent [\#292](https://github.com/shelljs/shelljs/pull/292) ([nfischer](https://github.com/nfischer)) +- update `exec` docs to match implemented behaviour [\#289](https://github.com/shelljs/shelljs/pull/289) ([vise890](https://github.com/vise890)) +- chore: update github URL in package.json [\#288](https://github.com/shelljs/shelljs/pull/288) ([nfischer](https://github.com/nfischer)) +- docs\(spelling\): fix typo in source comment [\#285](https://github.com/shelljs/shelljs/pull/285) ([nfischer](https://github.com/nfischer)) +- chore\(travis\): add OS X to Travis CI [\#283](https://github.com/shelljs/shelljs/pull/283) ([nfischer](https://github.com/nfischer)) +- Don't do `console.log.apply\(this, ...\)`. [\#274](https://github.com/shelljs/shelljs/pull/274) ([ariporad](https://github.com/ariporad)) +- Implementing cd\('-'\) to behave like Bash's "cd -" [\#273](https://github.com/shelljs/shelljs/pull/273) ([nfischer](https://github.com/nfischer)) +- Fix cp to match unix behavior [\#271](https://github.com/shelljs/shelljs/pull/271) ([freitagbr](https://github.com/freitagbr)) +- Commands that have multiple errors now produce cleaner log output [\#268](https://github.com/shelljs/shelljs/pull/268) ([nfischer](https://github.com/nfischer)) +- Support exit code in shjs. [\#252](https://github.com/shelljs/shelljs/pull/252) ([bryce-gibson](https://github.com/bryce-gibson)) +- add touch\(1\) [\#249](https://github.com/shelljs/shelljs/pull/249) ([blockloop](https://github.com/blockloop)) +- Fix `os.tmpdir` bug [\#240](https://github.com/shelljs/shelljs/pull/240) ([BYK](https://github.com/BYK)) +- Make sure Which\(\) on Windows platform always return the command with … [\#239](https://github.com/shelljs/shelljs/pull/239) ([TingluoHuang](https://github.com/TingluoHuang)) +- Add target node.js \(iojs v1, v2, v3\) [\#230](https://github.com/shelljs/shelljs/pull/230) ([sanemat](https://github.com/sanemat)) +- feat-multisymbolic + Support for directory entry \(capital X in chmod terms\) [\#228](https://github.com/shelljs/shelljs/pull/228) ([rezonant](https://github.com/rezonant)) +- Fixes an issue with multi-symbolic mode specification \(ie a-rwx,u+rw\) [\#227](https://github.com/shelljs/shelljs/pull/227) ([rezonant](https://github.com/rezonant)) +- Memoized the result of target invocation [\#216](https://github.com/shelljs/shelljs/pull/216) ([rizowski](https://github.com/rizowski)) +- remove empty for loop and leaked i var [\#166](https://github.com/shelljs/shelljs/pull/166) ([ratbeard](https://github.com/ratbeard)) +- Wrap script name in double quotes [\#135](https://github.com/shelljs/shelljs/pull/135) ([ndelitski](https://github.com/ndelitski)) +- Fixed coffeescript syntax in top example [\#99](https://github.com/shelljs/shelljs/pull/99) ([maxnordlund](https://github.com/maxnordlund)) +- fix\(touch\): enhance parseOptions and fix touch's -r flag [\#341](https://github.com/shelljs/shelljs/pull/341) ([nfischer](https://github.com/nfischer)) +- chore\(.npmignore\): update npmignore [\#339](https://github.com/shelljs/shelljs/pull/339) ([ariporad](https://github.com/ariporad)) +- Release v0.6.0 [\#338](https://github.com/shelljs/shelljs/pull/338) ([ariporad](https://github.com/ariporad)) +- docs\(README\): remove coffeescript from README [\#337](https://github.com/shelljs/shelljs/pull/337) ([ariporad](https://github.com/ariporad)) +- fix\(cp\): add -n option, make -f default behavior [\#336](https://github.com/shelljs/shelljs/pull/336) ([nfischer](https://github.com/nfischer)) +- feat\(exec\): allow all exec options to pass through [\#335](https://github.com/shelljs/shelljs/pull/335) ([nfischer](https://github.com/nfischer)) +- fix\(mv\): add -n option, make -f default behavior [\#328](https://github.com/shelljs/shelljs/pull/328) ([nfischer](https://github.com/nfischer)) +- fix\(cat\): make behavior more like unix [\#326](https://github.com/shelljs/shelljs/pull/326) ([nfischer](https://github.com/nfischer)) +- feat\(ls\): add -l option [\#324](https://github.com/shelljs/shelljs/pull/324) ([nfischer](https://github.com/nfischer)) +- style\(test/which\): make test/which.js conform to the style guidelines [\#320](https://github.com/shelljs/shelljs/pull/320) ([ariporad](https://github.com/ariporad)) +- chore\(appveyor\): add badge [\#316](https://github.com/shelljs/shelljs/pull/316) ([nfischer](https://github.com/nfischer)) +- fix\(windows\): fix shjs commands for windows [\#315](https://github.com/shelljs/shelljs/pull/315) ([nfischer](https://github.com/nfischer)) +- feat\(sed\): support multiple file names [\#314](https://github.com/shelljs/shelljs/pull/314) ([nfischer](https://github.com/nfischer)) +- feat\(cd\): cd\(\) \(no args\) changes to home directory [\#306](https://github.com/shelljs/shelljs/pull/306) ([nfischer](https://github.com/nfischer)) +- test\(shjs\): add tests for shjs [\#304](https://github.com/shelljs/shelljs/pull/304) ([ariporad](https://github.com/ariporad)) +- fix: regexes are more consistent with sed and grep [\#303](https://github.com/shelljs/shelljs/pull/303) ([nfischer](https://github.com/nfischer)) +- Add appveyor.yml config file [\#299](https://github.com/shelljs/shelljs/pull/299) ([nfischer](https://github.com/nfischer)) +- Fix tests on Windows [\#297](https://github.com/shelljs/shelljs/pull/297) ([BYK](https://github.com/BYK)) +- Search PATHEXT instead of 3 hardcoded values [\#290](https://github.com/shelljs/shelljs/pull/290) ([isiahmeadows](https://github.com/isiahmeadows)) +- Fix relative symlinks [\#282](https://github.com/shelljs/shelljs/pull/282) ([freitagbr](https://github.com/freitagbr)) +- Make to and toEnd chainable [\#276](https://github.com/shelljs/shelljs/pull/276) ([TimothyGu](https://github.com/TimothyGu)) + +## [v0.5.3](https://github.com/shelljs/shelljs/tree/v0.5.3) (2015-08-11) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.5.2...v0.5.3) + +**Merged pull requests:** + +- Manually closing streams [\#222](https://github.com/shelljs/shelljs/pull/222) ([JulianLaval](https://github.com/JulianLaval)) + +## [v0.5.2](https://github.com/shelljs/shelljs/tree/v0.5.2) (2015-08-10) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.5.1...v0.5.2) + +**Closed issues:** + +- Cannot run shell.exec [\#217](https://github.com/shelljs/shelljs/issues/217) +- write after end: internal error [\#206](https://github.com/shelljs/shelljs/issues/206) + +**Merged pull requests:** + +- Update README.md [\#221](https://github.com/shelljs/shelljs/pull/221) ([giosh94mhz](https://github.com/giosh94mhz)) +- prevent internal error: write after end [\#214](https://github.com/shelljs/shelljs/pull/214) ([charlierudolph](https://github.com/charlierudolph)) + +## [v0.5.1](https://github.com/shelljs/shelljs/tree/v0.5.1) (2015-06-05) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.5.0...v0.5.1) + +**Closed issues:** + +- cd into home directory [\#9](https://github.com/shelljs/shelljs/issues/9) + +**Merged pull requests:** + +- Fix issue \#49: Retry rmdirSync on Windows for up to 1 second if files still exist. [\#179](https://github.com/shelljs/shelljs/pull/179) ([andreialecu](https://github.com/andreialecu)) + +## [v0.5.0](https://github.com/shelljs/shelljs/tree/v0.5.0) (2015-05-19) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.3.0...v0.5.0) + +**Closed issues:** + +- Enter text to prompt [\#203](https://github.com/shelljs/shelljs/issues/203) +- Find which shell is being used [\#195](https://github.com/shelljs/shelljs/issues/195) +- Pass command line params to the make tool [\#188](https://github.com/shelljs/shelljs/issues/188) +- Is it possible to call exec with a command containing new lines ? [\#177](https://github.com/shelljs/shelljs/issues/177) +- The installation would break on Windows 7 [\#161](https://github.com/shelljs/shelljs/issues/161) +- Q.ninvoke\(\) returns undefined [\#153](https://github.com/shelljs/shelljs/issues/153) +- installed shelljs on osx but reported error: npm ERR! 404 '%5B-g%5D' is not in the npm registry. [\#124](https://github.com/shelljs/shelljs/issues/124) +- "ln" not found \(OS X\) [\#106](https://github.com/shelljs/shelljs/issues/106) +- Using shelljs in a CLI app. [\#91](https://github.com/shelljs/shelljs/issues/91) + +**Merged pull requests:** + +- 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)) +- 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)) + +## [v0.3.0](https://github.com/shelljs/shelljs/tree/v0.3.0) (2014-05-08) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.6...v0.3.0) + +**Closed issues:** + +- grep\(\) should fully support globing [\#118](https://github.com/shelljs/shelljs/issues/118) +- sed\(\) could support replacement function [\#115](https://github.com/shelljs/shelljs/issues/115) +- How would you close an exec process that runs indefinitely? [\#113](https://github.com/shelljs/shelljs/issues/113) +- listen for intermittent output of a long-running child process [\#111](https://github.com/shelljs/shelljs/issues/111) +- Cannot find module 'shelljs' after installing shelljs with npm [\#109](https://github.com/shelljs/shelljs/issues/109) +- Massive CPU usage on exec\(\) windows [\#108](https://github.com/shelljs/shelljs/issues/108) +- cp skipping dot files? [\#79](https://github.com/shelljs/shelljs/issues/79) +- $variables in exec\(\) aren't handled correctly [\#11](https://github.com/shelljs/shelljs/issues/11) +- debug flag that prints commands instead of executing [\#8](https://github.com/shelljs/shelljs/issues/8) + +**Merged pull requests:** + +- grep\(\) support for globing, fixes \#118 [\#119](https://github.com/shelljs/shelljs/pull/119) ([utensil](https://github.com/utensil)) +- make sed\(\) support replacement function, fixes \#115 [\#117](https://github.com/shelljs/shelljs/pull/117) ([utensil](https://github.com/utensil)) +- which\(\) should only find files, not directories [\#110](https://github.com/shelljs/shelljs/pull/110) ([panrafal](https://github.com/panrafal)) +- Added the New BSD license to the package.json. [\#105](https://github.com/shelljs/shelljs/pull/105) ([keskival](https://github.com/keskival)) +- Added win32 support to ln [\#104](https://github.com/shelljs/shelljs/pull/104) ([jamon](https://github.com/jamon)) +- Fix ln using bad paths when given abspaths. [\#89](https://github.com/shelljs/shelljs/pull/89) ([Schoonology](https://github.com/Schoonology)) +- Add ln support, including both -s and -f options. [\#88](https://github.com/shelljs/shelljs/pull/88) ([Schoonology](https://github.com/Schoonology)) +- add support for symlinking \(junctions\) on win32 [\#87](https://github.com/shelljs/shelljs/pull/87) ([jamon](https://github.com/jamon)) + +## [v0.2.6](https://github.com/shelljs/shelljs/tree/v0.2.6) (2013-09-22) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.5...v0.2.6) + +**Closed issues:** + +- Versions 0.2.4 and 0.2.3 keep throwing strange errors [\#82](https://github.com/shelljs/shelljs/issues/82) +- Add global pollution tests [\#33](https://github.com/shelljs/shelljs/issues/33) + +## [v0.2.5](https://github.com/shelljs/shelljs/tree/v0.2.5) (2013-09-11) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.4...v0.2.5) + +**Closed issues:** + +- shelljs.exec stalls on Red Hat when script is invoked with 'sudo -u username' [\#72](https://github.com/shelljs/shelljs/issues/72) + +## [v0.2.4](https://github.com/shelljs/shelljs/tree/v0.2.4) (2013-09-11) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.3...v0.2.4) + +## [v0.2.3](https://github.com/shelljs/shelljs/tree/v0.2.3) (2013-09-09) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.2.2...v0.2.3) + +**Merged pull requests:** + +- Make shell.exec\(\) treat process error return codes as shelljs errors [\#80](https://github.com/shelljs/shelljs/pull/80) ([nilsbunger](https://github.com/nilsbunger)) + +## [v0.2.2](https://github.com/shelljs/shelljs/tree/v0.2.2) (2013-09-02) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.4...v0.2.2) + +**Closed issues:** + +- which and node\_modules [\#63](https://github.com/shelljs/shelljs/issues/63) +- cannot install with nodejs 0.10.2 [\#57](https://github.com/shelljs/shelljs/issues/57) + +**Merged pull requests:** + +- Addition of a toEnd\(\) function modeled after the Unix \>\> pipe. [\#78](https://github.com/shelljs/shelljs/pull/78) ([andreweduffy](https://github.com/andreweduffy)) +- Added appendTo\(\) function to imitate '\>\>' redirect-and-append pipe. [\#75](https://github.com/shelljs/shelljs/pull/75) ([andreweduffy](https://github.com/andreweduffy)) +- Fix a small typo in README.md [\#71](https://github.com/shelljs/shelljs/pull/71) ([asmblah](https://github.com/asmblah)) +- adding an `.npmignore` file [\#70](https://github.com/shelljs/shelljs/pull/70) ([stephenmathieson](https://github.com/stephenmathieson)) +- tempdir: use `os.tmpDir` when possible [\#67](https://github.com/shelljs/shelljs/pull/67) ([stephenmathieson](https://github.com/stephenmathieson)) + +## [v0.1.4](https://github.com/shelljs/shelljs/tree/v0.1.4) (2013-05-10) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.3...v0.1.4) + +**Merged pull requests:** + +- removing extra fs calls [\#62](https://github.com/shelljs/shelljs/pull/62) ([stephenmathieson](https://github.com/stephenmathieson)) +- moving \_jshint\_ to a development dependency [\#61](https://github.com/shelljs/shelljs/pull/61) ([stephenmathieson](https://github.com/stephenmathieson)) +- Make the maximum buffersize 20 MB. [\#59](https://github.com/shelljs/shelljs/pull/59) ([waddlesplash](https://github.com/waddlesplash)) + +## [v0.1.3](https://github.com/shelljs/shelljs/tree/v0.1.3) (2013-04-21) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.2...v0.1.3) + +**Merged pull requests:** + +- test\('-L', badlink\) should return true [\#56](https://github.com/shelljs/shelljs/pull/56) ([lge88](https://github.com/lge88)) +- exec options now allows `silent:true` with callback. [\#54](https://github.com/shelljs/shelljs/pull/54) ([iapain](https://github.com/iapain)) +- Add Zepto to README [\#53](https://github.com/shelljs/shelljs/pull/53) ([madrobby](https://github.com/madrobby)) + +## [v0.1.2](https://github.com/shelljs/shelljs/tree/v0.1.2) (2013-01-08) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.1...v0.1.2) + +**Closed issues:** + +- pushd/popd [\#24](https://github.com/shelljs/shelljs/issues/24) + +**Merged pull requests:** + +- Implemented chmod command. Github issue 35 [\#48](https://github.com/shelljs/shelljs/pull/48) ([brandonramirez](https://github.com/brandonramirez)) + +## [v0.1.1](https://github.com/shelljs/shelljs/tree/v0.1.1) (2013-01-01) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.1.0...v0.1.1) + +**Merged pull requests:** + +- Work in progress: pushd/popd/dirs [\#47](https://github.com/shelljs/shelljs/pull/47) ([mstade](https://github.com/mstade)) + +## [v0.1.0](https://github.com/shelljs/shelljs/tree/v0.1.0) (2012-12-26) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.9...v0.1.0) + +**Closed issues:** + +- test\(\) for binary file? [\#45](https://github.com/shelljs/shelljs/issues/45) +- Inconsistent behaviour of cp command with directories. [\#44](https://github.com/shelljs/shelljs/issues/44) +- Executing SSH with ShellJs [\#43](https://github.com/shelljs/shelljs/issues/43) + +**Merged pull requests:** + +- Fix for \#44 [\#46](https://github.com/shelljs/shelljs/pull/46) ([mstade](https://github.com/mstade)) +- Fix single/double quotes in exec [\#42](https://github.com/shelljs/shelljs/pull/42) ([danielepolencic](https://github.com/danielepolencic)) + +## [v0.0.9](https://github.com/shelljs/shelljs/tree/v0.0.9) (2012-12-01) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.8...v0.0.9) + +**Closed issues:** + +- silent output [\#40](https://github.com/shelljs/shelljs/issues/40) +- asynchronous exec [\#34](https://github.com/shelljs/shelljs/issues/34) + +**Merged pull requests:** + +- Passed process arguments to executable script [\#36](https://github.com/shelljs/shelljs/pull/36) ([Zanisimo](https://github.com/Zanisimo)) + +## [v0.0.8](https://github.com/shelljs/shelljs/tree/v0.0.8) (2012-10-11) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.7...v0.0.8) + +**Closed issues:** + +- 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) + +**Merged pull requests:** + +- fix: global leak 'stats' [\#29](https://github.com/shelljs/shelljs/pull/29) ([ando-takahiro](https://github.com/ando-takahiro)) +- -a includes . and ..; -A does not [\#28](https://github.com/shelljs/shelljs/pull/28) ([aeosynth](https://github.com/aeosynth)) + +## [v0.0.7](https://github.com/shelljs/shelljs/tree/v0.0.7) (2012-09-23) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.6...v0.0.7) + +**Closed issues:** + +- 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:** + +- add primaries to \_test [\#23](https://github.com/shelljs/shelljs/pull/23) ([aeosynth](https://github.com/aeosynth)) + +## [v0.0.6](https://github.com/shelljs/shelljs/tree/v0.0.6) (2012-08-07) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.6pre2...v0.0.6) + +**Merged pull requests:** + +- Fixed a global variable leak [\#16](https://github.com/shelljs/shelljs/pull/16) ([dallonf](https://github.com/dallonf)) + +## [v0.0.6pre2](https://github.com/shelljs/shelljs/tree/v0.0.6pre2) (2012-05-25) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.6pre1...v0.0.6pre2) + +## [v0.0.6pre1](https://github.com/shelljs/shelljs/tree/v0.0.6pre1) (2012-05-25) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5...v0.0.6pre1) + +## [v0.0.5](https://github.com/shelljs/shelljs/tree/v0.0.5) (2012-05-24) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5pre4...v0.0.5) + +**Closed issues:** + +- global.key assigned value 'async' as a result of shell.exec\(...\) [\#12](https://github.com/shelljs/shelljs/issues/12) + +**Merged pull requests:** + +- Add support for grep option -v. [\#13](https://github.com/shelljs/shelljs/pull/13) ([kkujala](https://github.com/kkujala)) + +## [v0.0.5pre4](https://github.com/shelljs/shelljs/tree/v0.0.5pre4) (2012-03-27) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5pre3...v0.0.5pre4) + +## [v0.0.5pre3](https://github.com/shelljs/shelljs/tree/v0.0.5pre3) (2012-03-27) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5pre2...v0.0.5pre3) + +## [v0.0.5pre2](https://github.com/shelljs/shelljs/tree/v0.0.5pre2) (2012-03-26) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.5pre1...v0.0.5pre2) + +## [v0.0.5pre1](https://github.com/shelljs/shelljs/tree/v0.0.5pre1) (2012-03-26) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.4...v0.0.5pre1) + +**Closed issues:** + +- rm\(\) does not respect read/write modes [\#6](https://github.com/shelljs/shelljs/issues/6) + +## [v0.0.4](https://github.com/shelljs/shelljs/tree/v0.0.4) (2012-03-22) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.3...v0.0.4) + +**Closed issues:** + +- "For convenient iteration via `for in`, ..."? [\#4](https://github.com/shelljs/shelljs/issues/4) + +## [v0.0.3](https://github.com/shelljs/shelljs/tree/v0.0.3) (2012-03-21) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.2...v0.0.3) + +## [v0.0.2](https://github.com/shelljs/shelljs/tree/v0.0.2) (2012-03-15) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.0.2pre1...v0.0.2) + +## [v0.0.2pre1](https://github.com/shelljs/shelljs/tree/v0.0.2pre1) (2012-03-03) + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file From 2134bd3da11f1423a2a41042d7bf747b1d3fd59f Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Fri, 13 Jan 2017 16:28:04 -0800 Subject: [PATCH 003/108] docs(release): use bulleted list (#643) --- RELEASE.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index c78d364f4..90802c33c 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -4,10 +4,9 @@ 2. `npm run gendocs` 3. Bump version, create tags, push, and release: - `$ npm run ` - - >`major` - breaking API changes - >`minor` - backwards-compatible features - >`patch` - backwards-compatible bug fixes + - `major` - breaking API changes + - `minor` - backwards-compatible features + - `patch` - backwards-compatible bug fixes 4. Update CHANGELOG.md - `$ npm run changelog` - `$ git push` From 84ffb386eb7c3f22633f3a18f85a1f43257d48f8 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 16 Jan 2017 12:45:14 -0800 Subject: [PATCH 004/108] chore(lint): Enforce a trailing comma for multi-line (#646) --- .eslintrc.json | 2 +- src/chmod.js | 6 +++--- src/common.js | 4 ++-- src/dirs.js | 6 +++--- src/exec.js | 6 +++--- src/set.js | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 411b11ae0..e712eeab2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,7 @@ }, "extends": "airbnb-base/legacy", "rules": { - "comma-dangle": 0, + "comma-dangle": [2, "always-multiline"], "global-require": 0, "vars-on-top": 0, "spaced-comment": [2, "always", { "markers": ["@", "@include"], "exceptions": ["@", "@commands"] }], diff --git a/src/chmod.js b/src/chmod.js index a1afd90e7..a494cefb2 100644 --- a/src/chmod.js +++ b/src/chmod.js @@ -21,12 +21,12 @@ var PERMS = (function (base) { SETGID: parseInt('02000', 8), SETUID: parseInt('04000', 8), - TYPE_MASK: parseInt('0770000', 8) + TYPE_MASK: parseInt('0770000', 8), }; }({ EXEC: 1, WRITE: 2, - READ: 4 + READ: 4, })); common.register('chmod', _chmod, { @@ -73,7 +73,7 @@ function _chmod(options, mode, filePattern) { options = common.parseOptions(options, { 'R': 'recursive', 'c': 'changes', - 'v': 'verbose' + 'v': 'verbose', }); filePattern = [].slice.call(arguments, 2); diff --git a/src/common.js b/src/common.js index 66b541a1e..8b07421a9 100644 --- a/src/common.js +++ b/src/common.js @@ -60,7 +60,7 @@ var state = { error: null, errorCode: 0, currentCmd: 'shell.js', - tempDir: null + tempDir: null, }; exports.state = state; @@ -115,7 +115,7 @@ function error(msg, _code, options) { if (!options.continue) { throw { msg: 'earlyExit', - retValue: (new ShellString('', state.error, state.errorCode)) + retValue: (new ShellString('', state.error, state.errorCode)), }; } } diff --git a/src/dirs.js b/src/dirs.js index cf5fe02f5..3806c14f7 100644 --- a/src/dirs.js +++ b/src/dirs.js @@ -63,7 +63,7 @@ function _pushd(options, dir) { } options = common.parseOptions(options, { - 'n': 'no-cd' + 'n': 'no-cd', }); var dirs = _actualDirStack(); @@ -129,7 +129,7 @@ function _popd(options, index) { } options = common.parseOptions(options, { - 'n': 'no-cd' + 'n': 'no-cd', }); if (!_dirStack.length) { @@ -172,7 +172,7 @@ function _dirs(options, index) { } options = common.parseOptions(options, { - 'c': 'clear' + 'c': 'clear', }); if (options.clear) { diff --git a/src/exec.js b/src/exec.js index 9c9128fea..aade0228c 100644 --- a/src/exec.js +++ b/src/exec.js @@ -34,7 +34,7 @@ function execSync(cmd, opts, pipe) { silent: common.config.silent, cwd: _pwd().toString(), env: process.env, - maxBuffer: DEFAULT_MAXBUFFER_SIZE + maxBuffer: DEFAULT_MAXBUFFER_SIZE, }, opts); var previousStdoutContent = ''; @@ -190,7 +190,7 @@ function execAsync(cmd, opts, pipe, callback) { silent: common.config.silent, cwd: _pwd().toString(), env: process.env, - maxBuffer: DEFAULT_MAXBUFFER_SIZE + maxBuffer: DEFAULT_MAXBUFFER_SIZE, }, opts); var c = child.exec(cmd, opts, function (err) { @@ -279,7 +279,7 @@ function _exec(command, options, callback) { options = common.extend({ silent: common.config.silent, - async: false + async: false, }, options); try { diff --git a/src/set.js b/src/set.js index 3402cd660..238e23e4a 100644 --- a/src/set.js +++ b/src/set.js @@ -34,7 +34,7 @@ function _set(options) { options = common.parseOptions(options, { 'e': 'fatal', 'v': 'verbose', - 'f': 'noglob' + 'f': 'noglob', }); if (negate) { From 055156f7f597ca5a5ddfe49f5004678d227849ef Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Thu, 2 Feb 2017 15:21:58 -0800 Subject: [PATCH 005/108] Fix find ENOENT (#654) * Add find: nonexistant path test * Catch statSync errors, return shell error --- src/find.js | 9 ++++++++- test/find.js | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/find.js b/src/find.js index f96a51e78..625aa2972 100644 --- a/src/find.js +++ b/src/find.js @@ -40,9 +40,16 @@ function _find(options, paths) { // to get the base dir in the output, we need instead ls('-R', 'dir/*') for every directory paths.forEach(function (file) { + var stat; + try { + stat = fs.statSync(file); + } catch (e) { + common.error('no such file or directory: ' + file); + } + pushFile(file); - if (fs.statSync(file).isDirectory()) { + if (stat.isDirectory()) { _ls({ recursive: true, all: true }, file).forEach(function (subfile) { pushFile(path.join(file, subfile)); }); diff --git a/test/find.js b/test/find.js index 5e65bd9ec..a37dcd314 100644 --- a/test/find.js +++ b/test/find.js @@ -60,3 +60,9 @@ test('multiple paths - array', t => { t.truthy(result.indexOf('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'); + t.is(result.code, 1); +}); From 8dd2488ec54ec56e18b5a72ee3ecc7d9c11668fb Mon Sep 17 00:00:00 2001 From: Stanislav Termosa Date: Fri, 10 Feb 2017 21:32:22 +0300 Subject: [PATCH 006/108] feature: add -a option for which command (#655) * feature: add -a option for which command * chore(test): test which -a with unexisting name * chore(test): check which -a has same result as regular one * chord(test): fix errors mentioned by eslint --- src/which.js | 43 +++++++++++++++++++++++++++++++------------ test/which.js | 25 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/which.js b/src/which.js index ef5d185eb..2f3f12147 100644 --- a/src/which.js +++ b/src/which.js @@ -4,6 +4,9 @@ var path = require('path'); common.register('which', _which, { allowGlobbing: false, + cmdOptions: { + 'a': 'all', + }, }); // XP's system default value for PATHEXT system variable, just in case it's not @@ -42,13 +45,14 @@ function _which(options, cmd) { var pathEnv = process.env.path || process.env.Path || process.env.PATH; var pathArray = splitPath(pathEnv); - var where = null; + var all = options.all; + var where = all ? [] : null; // No relative/absolute paths provided? if (cmd.search(/\//) === -1) { // Search for command in PATH pathArray.forEach(function (dir) { - if (where) return; // already found it + if (!all && where) return; // already found it var attempt = path.resolve(dir, cmd); @@ -65,8 +69,12 @@ function _which(options, cmd) { for (i = 0; i < pathExtArray.length; i++) { var ext = pathExtArray[i]; if (attempt.slice(-ext.length) === ext && checkPath(attempt)) { - where = attempt; - return; + if (all) { + where.push(attempt); + } else { + where = attempt; + return; + } } } @@ -75,25 +83,36 @@ function _which(options, cmd) { for (i = 0; i < pathExtArray.length; i++) { attempt = baseAttempt + pathExtArray[i]; if (checkPath(attempt)) { - where = attempt; - return; + if (all) { + where.push(attempt); + } else { + where = attempt; + return; + } } } } else { // Assume it's Unix-like if (checkPath(attempt)) { - where = attempt; - return; + if (all) { + where.push(attempt); + } else { + where = attempt; + return; + } } } }); } - // Command not found anywhere? - if (!checkPath(cmd) && !where) return null; - - where = where || path.resolve(cmd); + if (all && where.length) return where; + if (!all && where) return where; + // Command not found anywhere? + if (checkPath(cmd)) { + where = path.resolve(cmd); + if (all) where = [where]; + } return where; } module.exports = _which; diff --git a/test/which.js b/test/which.js index 13b92c7bf..705fda311 100644 --- a/test/which.js +++ b/test/which.js @@ -45,3 +45,28 @@ test('Windows can search with or without a .exe extension', t => { t.is(node.toString(), nodeExe.toString()); } }); + +test('Searching with -a flag returns an array', t => { + const commandName = 'node'; // Should be an existing command + const result = shell.which('-a', commandName); + t.falsy(shell.error()); + t.truthy(result); + t.not(result.length, 0); +}); + +test('Searching with -a flag for not existing command returns an empty array', t => { + const notExist = '6ef25c13209cb28ae465852508cc3a8f3dcdc71bc7bcf8c38379ba38me'; + const result = shell.which('-a', notExist); + t.falsy(shell.error()); + t.is(result.length, 0); +}); + +test('Searching with -a flag returns an array with first item equals to the regular search', t => { + const commandName = 'node'; // Should be an existing command + const resultForWhich = shell.which(commandName); + const resultForWhichA = shell.which('-a', commandName); + t.falsy(shell.error()); + t.truthy(resultForWhich); + t.truthy(resultForWhichA); + t.is(resultForWhich.toString(), resultForWhichA[0].toString()); +}); From fdcc789882642ba43322d0e4cb162bae7b0ad2b1 Mon Sep 17 00:00:00 2001 From: Faheel Ahmad Date: Sat, 11 Feb 2017 13:47:46 +0530 Subject: [PATCH 007/108] Fix typo (#660) battled-tested -> battle-tested --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cf5a0dd77..84afca5c9 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Node projects - say goodbye to those gnarly Bash scripts! ShellJS is proudly tested on every node release since `v0.11`! -The project is [unit-tested](http://travis-ci.org/shelljs/shelljs) and battled-tested in projects like: +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 From 434ed592de7c0e85592a1dcb8cbb772a3c3189d7 Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Tue, 21 Feb 2017 01:45:46 +0200 Subject: [PATCH 008/108] docs(chmod): document `options` argument (#663) --- README.md | 5 +++-- src/chmod.js | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 84afca5c9..f0884bb27 100644 --- a/README.md +++ b/README.md @@ -177,8 +177,8 @@ Changes to directory `dir` for the duration of the script. Changes to home directory if no argument is supplied. -### chmod(octal_mode || octal_string, file) -### chmod(symbolic_mode, file) +### chmod([options,] octal_mode || octal_string, file) +### chmod([options,] symbolic_mode, file) Available options: @@ -192,6 +192,7 @@ Examples: chmod(755, '/Users/brandon'); chmod('755', '/Users/brandon'); // same as above chmod('u+x', '/Users/brandon'); +chmod('-R', 'a-w', '/Users/brandon'); ``` Alters the permissions of a file or directory by either specifying the diff --git a/src/chmod.js b/src/chmod.js index a494cefb2..ce5659e35 100644 --- a/src/chmod.js +++ b/src/chmod.js @@ -33,8 +33,8 @@ common.register('chmod', _chmod, { }); //@ -//@ ### chmod(octal_mode || octal_string, file) -//@ ### chmod(symbolic_mode, file) +//@ ### chmod([options,] octal_mode || octal_string, file) +//@ ### chmod([options,] symbolic_mode, file) //@ //@ Available options: //@ @@ -48,6 +48,7 @@ common.register('chmod', _chmod, { //@ chmod(755, '/Users/brandon'); //@ chmod('755', '/Users/brandon'); // same as above //@ chmod('u+x', '/Users/brandon'); +//@ chmod('-R', 'a-w', '/Users/brandon'); //@ ``` //@ //@ Alters the permissions of a file or directory by either specifying the From 006b8c2460b6f31296cdc941d8dbaddbce3d50c4 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 27 Feb 2017 13:23:30 -0800 Subject: [PATCH 009/108] docs: clean up RELEASE.md (#662) Miscellaneous changes. --- RELEASE.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 90802c33c..80aae7f7b 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,14 +1,14 @@ # Release steps 1. Ensure master passes CI tests -2. `npm run gendocs` -3. Bump version, create tags, push, and release: +2. Bump version, create tags, push, and release: - `$ npm run ` - `major` - breaking API changes - `minor` - backwards-compatible features - `patch` - backwards-compatible bug fixes -4. Update CHANGELOG.md +3. Update `CHANGELOG.md` - `$ npm run changelog` + - Manually verify that the changelog makes sense - `$ git push` -5. Generate the documentup website by visiting - [http://documentup.com/shelljs/shelljs/__recompile] in your browser +4. Generate the documentup website by visiting + http://documentup.com/shelljs/shelljs/__recompile in your browser From df06ac4a8a011b38f701b3fbc852cefa3e964091 Mon Sep 17 00:00:00 2001 From: Fran Dios Date: Tue, 28 Feb 2017 13:53:32 +0900 Subject: [PATCH 010/108] ls -L (follow symlinks) (#665) * feat: -L (follow symlinks) option for ls * test: ls -L option * docs: Add ls -L option to readme * fix: ls -L ternary operator * Revert "test: ls -L option" This reverts commit dbb057ac087b23aa2c1358018d3c832dd546c5f2. * test: ls -L option * test: Remove duplicate test --- README.md | 1 + src/ls.js | 8 +++++--- test/ls.js | 32 +++++++++++++++++++++++--------- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f0884bb27..b0fee0346 100644 --- a/README.md +++ b/README.md @@ -418,6 +418,7 @@ Available options: + `-R`: recursive + `-A`: all files (include files beginning with `.`, except for `.` and `..`) ++ `-L`: follow symlinks + `-d`: list directories themselves, not their contents + `-l`: list objects representing each file, each with fields containing `ls -l` output fields. See diff --git a/src/ls.js b/src/ls.js index 7f25056cd..cd2d9202e 100644 --- a/src/ls.js +++ b/src/ls.js @@ -9,6 +9,7 @@ common.register('ls', _ls, { cmdOptions: { 'R': 'recursive', 'A': 'all', + 'L': 'link', 'a': 'all_deprecated', 'd': 'directory', 'l': 'long', @@ -22,6 +23,7 @@ common.register('ls', _ls, { //@ //@ + `-R`: recursive //@ + `-A`: all files (include files beginning with `.`, except for `.` and `..`) +//@ + `-L`: follow symlinks //@ + `-d`: list directories themselves, not their contents //@ + `-l`: list objects representing each file, each with fields containing `ls //@ -l` output fields. See @@ -60,7 +62,7 @@ function _ls(options, paths) { relName = relName.replace(/\\/g, '/'); } if (options.long) { - stat = stat || fs.lstatSync(abs); + stat = stat || (options.link ? fs.statSync(abs) : fs.lstatSync(abs)); list.push(addLsAttributes(relName, stat)); } else { // list.push(path.relative(rel || '.', file)); @@ -72,7 +74,7 @@ function _ls(options, paths) { var stat; try { - stat = fs.lstatSync(p); + stat = options.link ? fs.statSync(p) : fs.lstatSync(p); } catch (e) { common.error('no such file or directory: ' + p, 2, { continue: true }); return; @@ -82,7 +84,7 @@ function _ls(options, paths) { if (stat.isDirectory() && !options.directory) { if (options.recursive) { // use glob, because it's simple - glob.sync(p + globPatternRecursive, { dot: options.all }) + glob.sync(p + globPatternRecursive, { dot: options.all, follow: options.link }) .forEach(function (item) { pushFile(item, path.relative(p, item)); }); diff --git a/test/ls.js b/test/ls.js index a50f27006..05d24763f 100644 --- a/test/ls.js +++ b/test/ls.js @@ -271,7 +271,7 @@ test('recursive, no path', t => { t.is(result.length, 9); }); -test('recusive, path given', t => { +test('recursive, path given', t => { const result = shell.ls('-R', 'resources/ls'); t.falsy(shell.error()); t.is(result.code, 0); @@ -292,14 +292,28 @@ test('-RA flag, path given', t => { t.is(result.length, 14); }); -test('recursive, wildcard', t => { - const result = shell.ls('-R', 'resources/ls'); - t.falsy(shell.error()); - t.is(result.code, 0); - t.truthy(result.indexOf('a_dir') > -1); - t.truthy(result.indexOf('a_dir/b_dir') > -1); - t.truthy(result.indexOf('a_dir/b_dir/z') > -1); - t.is(result.length, 9); +test('-RAL flag, path given', t => { + if (process.platform !== 'win32') { + const result = shell.ls('-RAL', 'resources/rm'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.truthy(result.indexOf('a_dir') > -1); + t.truthy(result.indexOf('a_dir/a_file') > -1); + t.truthy(result.indexOf('link_to_a_dir') > -1); + 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') { + 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 => { From 2d0428b1c9810ca8ca25c73737ee3035874da34c Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 28 Feb 2017 01:34:51 -0800 Subject: [PATCH 011/108] Switch commands.json -> commands.js (#668) WebPack has issues with importing JSON directly and using JavaScript methods on it. For this reason, using the `.forEach()` method on the imported JSON array caused a method-not-found error. Instead, we can make this a real JavaScript array by keeping it in a JavaScript file and exporting it as a field. It should be noted that exporting it as `exports = [...]` does not work, because Node won't actually interpret it as a JavaScript array (with the required methods). So instead we can export it as `exports.list = [...]` and access the `list` field to get the real JavaScript array of command names. Fixes #667 --- commands.js | 29 +++++++++++++++++++++++++++++ commands.json | 29 ----------------------------- package.json | 2 +- scripts/generate-docs.js | 2 +- shell.js | 2 +- 5 files changed, 32 insertions(+), 32 deletions(-) create mode 100644 commands.js delete mode 100644 commands.json diff --git a/commands.js b/commands.js new file mode 100644 index 000000000..f31adb214 --- /dev/null +++ b/commands.js @@ -0,0 +1,29 @@ +module.exports = [ + 'cat', + 'cd', + 'chmod', + 'cp', + 'dirs', + 'echo', + 'exec', + 'find', + 'grep', + 'head', + 'ln', + 'ls', + 'mkdir', + 'mv', + 'pwd', + 'rm', + 'sed', + 'set', + 'sort', + 'tail', + 'tempdir', + 'test', + 'to', + 'toEnd', + 'touch', + 'uniq', + 'which', +]; diff --git a/commands.json b/commands.json deleted file mode 100644 index 9254e92dd..000000000 --- a/commands.json +++ /dev/null @@ -1,29 +0,0 @@ -[ - "cat", - "cd", - "chmod", - "cp", - "dirs", - "echo", - "exec", - "find", - "grep", - "head", - "ln", - "ls", - "mkdir", - "mv", - "pwd", - "rm", - "sed", - "set", - "sort", - "tail", - "tempdir", - "test", - "to", - "toEnd", - "touch", - "uniq", - "which" -] diff --git a/package.json b/package.json index af41a52bd..950d695fe 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "homepage": "http://github.com/shelljs/shelljs", "main": "./shell.js", "files": [ - "commands.json", + "commands.js", "global.js", "make.js", "plugin.js", diff --git a/scripts/generate-docs.js b/scripts/generate-docs.js index 9b31f1701..6f6b36de3 100755 --- a/scripts/generate-docs.js +++ b/scripts/generate-docs.js @@ -11,7 +11,7 @@ var docs = grep('^//@', 'shell.js'); // Insert the docs for all the registered commands docs = docs.replace(/\/\/@commands\n/g, function () { - return require('../commands.json').map(function (commandName) { + return require('../commands').map(function (commandName) { var file = './src/' + commandName + '.js'; return grep('^//@', file) + '\n'; }).join(''); diff --git a/shell.js b/shell.js index 44bfbdc78..f155f3d3a 100644 --- a/shell.js +++ b/shell.js @@ -21,7 +21,7 @@ var common = require('./src/common'); //@commands // Load all default commands -require('./commands.json').forEach(function (command) { +require('./commands').forEach(function (command) { require('./src/' + command); }); From 172d0f15432a236438f2b239eeaa1cf7ce44fc93 Mon Sep 17 00:00:00 2001 From: Fran Dios Date: Wed, 1 Mar 2017 10:32:02 +0900 Subject: [PATCH 012/108] Modified glob pattern. Fixes #666 (#676) --- src/ls.js | 7 +++++-- test/ls.js | 14 +++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/ls.js b/src/ls.js index cd2d9202e..bb1b6a7bd 100644 --- a/src/ls.js +++ b/src/ls.js @@ -3,7 +3,7 @@ var fs = require('fs'); var common = require('./common'); var glob = require('glob'); -var globPatternRecursive = path.sep + '**' + path.sep + '*'; +var globPatternRecursive = path.sep + '**'; common.register('ls', _ls, { cmdOptions: { @@ -86,7 +86,10 @@ function _ls(options, paths) { // use glob, because it's simple glob.sync(p + globPatternRecursive, { dot: options.all, follow: options.link }) .forEach(function (item) { - pushFile(item, path.relative(p, item)); + // Glob pattern returns the directory itself and needs to be filtered out. + if (path.relative(p, item)) { + pushFile(item, path.relative(p, item)); + } }); } else if (options.all) { // use fs.readdirSync, because it's fast diff --git a/test/ls.js b/test/ls.js index 05d24763f..4285ea0a6 100644 --- a/test/ls.js +++ b/test/ls.js @@ -292,7 +292,19 @@ test('-RA flag, path given', t => { t.is(result.length, 14); }); -test('-RAL flag, path given', t => { +test('-RA flag, symlinks are not followed', t => { + const result = shell.ls('-RA', 'resources/rm'); + t.falsy(shell.error()); + t.is(result.code, 0); + t.truthy(result.indexOf('a_dir') > -1); + t.truthy(result.indexOf('a_dir/a_file') > -1); + t.truthy(result.indexOf('link_to_a_dir') > -1); + t.is(result.indexOf('link_to_a_dir/a_file'), -1); + t.truthy(result.indexOf('fake.lnk') > -1); + t.is(result.length, 4); +}); + +test('-RAL flag, follows symlinks', t => { if (process.platform !== 'win32') { const result = shell.ls('-RAL', 'resources/rm'); t.falsy(shell.error()); From 3cd4470be3bd33692f339c8800f1b340cfac11fc Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 4 Mar 2017 00:14:20 -0800 Subject: [PATCH 013/108] refactor: reduce repeated code in which() (#659) Use path.delimiter instead of explicit conditional. Try to reuse repeated code blocks. Fixes #656 --- src/which.js | 102 +++++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 61 deletions(-) diff --git a/src/which.js b/src/which.js index 2f3f12147..03db57bcd 100644 --- a/src/which.js +++ b/src/which.js @@ -15,13 +15,7 @@ var XP_DEFAULT_PATHEXT = '.com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh'; // Cross-platform method for splitting environment PATH variables function splitPath(p) { - if (!p) return []; - - if (common.platform === 'win') { - return p.split(';'); - } else { - return p.split(':'); - } + return p ? p.split(path.delimiter) : []; } function checkPath(pathName) { @@ -45,74 +39,60 @@ function _which(options, cmd) { var pathEnv = process.env.path || process.env.Path || process.env.PATH; var pathArray = splitPath(pathEnv); - var all = options.all; - var where = all ? [] : null; + + var queryMatches = []; // No relative/absolute paths provided? - if (cmd.search(/\//) === -1) { + if (cmd.indexOf('/') === -1) { + // Assume that there are no extensions to append to queries (this is the + // case for unix) + var pathExtArray = ['']; + if (common.platform === 'win') { + // In case the PATHEXT variable is somehow not set (e.g. + // child_process.spawn with an empty environment), use the XP default. + var pathExtEnv = process.env.PATHEXT || XP_DEFAULT_PATHEXT; + pathExtArray = splitPath(pathExtEnv.toUpperCase()); + } + // Search for command in PATH - pathArray.forEach(function (dir) { - if (!all && where) return; // already found it + for (var k = 0; k < pathArray.length; k++) { + // already found it + if (queryMatches.length > 0 && !options.all) break; - var attempt = path.resolve(dir, cmd); + var attempt = path.resolve(pathArray[k], cmd); if (common.platform === 'win') { attempt = attempt.toUpperCase(); + } - // In case the PATHEXT variable is somehow not set (e.g. - // child_process.spawn with an empty environment), use the XP default. - var pathExtEnv = process.env.PATHEXT || XP_DEFAULT_PATHEXT; - var pathExtArray = splitPath(pathExtEnv.toUpperCase()); - var i; - - // If the extension is already in PATHEXT, just return that. - for (i = 0; i < pathExtArray.length; i++) { - var ext = pathExtArray[i]; - if (attempt.slice(-ext.length) === ext && checkPath(attempt)) { - if (all) { - where.push(attempt); - } else { - where = attempt; - return; - } - } - } - - // Cycle through the PATHEXT variable - var baseAttempt = attempt; - for (i = 0; i < pathExtArray.length; i++) { - attempt = baseAttempt + pathExtArray[i]; - if (checkPath(attempt)) { - if (all) { - where.push(attempt); - } else { - where = attempt; - return; - } - } - } - } else { - // Assume it's Unix-like + var match = attempt.match(/\.[^<>:"/\|?*.]+$/); + if (match && pathExtArray.indexOf(match[0]) >= 0) { // this is Windows-only + // The user typed a query with the file extension, like + // `which('node.exe')` if (checkPath(attempt)) { - if (all) { - where.push(attempt); - } else { - where = attempt; - return; + queryMatches.push(attempt); + break; + } + } else { // All-platforms + // Cycle through the PATHEXT array, and check each extension + // Note: the array is always [''] on Unix + for (var i = 0; i < pathExtArray.length; i++) { + var ext = pathExtArray[i]; + var newAttempt = attempt + ext; + if (checkPath(newAttempt)) { + queryMatches.push(newAttempt); + break; } } } - }); + } + } else if (checkPath(cmd)) { // a valid absolute or relative path + queryMatches.push(path.resolve(cmd)); } - if (all && where.length) return where; - if (!all && where) return where; - - // Command not found anywhere? - if (checkPath(cmd)) { - where = path.resolve(cmd); - if (all) where = [where]; + if (queryMatches.length > 0) { + return options.all ? queryMatches : queryMatches[0]; } - return where; + return options.all ? [] : null; } module.exports = _which; From 5318fdc43a56a5f13655f105c7e2e1146452506d Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 4 Mar 2017 01:07:23 -0800 Subject: [PATCH 014/108] docs: miscellaneous README changes (#661) - Add @freitagbr to the bottom of the README - Remove docs about shjs (it's not well supported) - Remove docs about coffeescript (we don't do anything special for coffeescript anyway) - Modify the section about shelljs/global, since we strongly recommend avoiding this now - Rewrite the code example to use `require('shelljs')` instead of shelljs/global - Mention ESLint next to JSHint - Reformat sections with long lines to be 80 columns --- README.md | 99 +++++++++++++++++------------------------------------ src/exec.js | 2 +- 2 files changed, 33 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index b0fee0346..e8d8a0100 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,11 @@ [![npm version](https://img.shields.io/npm/v/shelljs.svg?style=flat-square)](https://www.npmjs.com/package/shelljs) [![npm downloads](https://img.shields.io/npm/dm/shelljs.svg?style=flat-square)](https://www.npmjs.com/package/shelljs) -ShellJS is a portable **(Windows/Linux/OS X)** implementation of Unix shell commands on top of the -Node.js API. You can use it to eliminate your shell 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 a portable **(Windows/Linux/OS X)** implementation of Unix shell +commands on top of the Node.js API. You can use it to eliminate your shell +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`! @@ -17,17 +18,17 @@ The project is [unit-tested](http://travis-ci.org/shelljs/shelljs) and battle-te + [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) - Most popular JavaScript linter ++ [JSHint](http://jshint.com) & [ESLint](http://eslint.org/) - popular JavaScript linters + [Zepto](http://zeptojs.com) - jQuery-compatible JavaScript library for modern browsers + [Yeoman](http://yeoman.io/) - Web application stack and development tool + [Deployd.com](http://deployd.com) - Open source PaaS for quick API backend generation + And [many more](https://npmjs.org/browse/depended/shelljs). -If you have feedback, suggestions, or need help, feel free to post in our [issue tracker](https://github.com/shelljs/shelljs/issues). +If you have feedback, suggestions, or need help, feel free to post in our [issue +tracker](https://github.com/shelljs/shelljs/issues). -Think ShellJS is cool? Check out some related projects (like -[cash](https://github.com/dthree/cash)--a javascript-based POSIX shell) -in our [Wiki page](https://github.com/shelljs/shelljs/wiki)! +Think ShellJS is cool? Check out some related projects in our [Wiki +page](https://github.com/shelljs/shelljs/wiki)! Upgrading from an older version? Check out our [breaking changes](https://github.com/shelljs/shelljs/wiki/Breaking-Changes) page to see @@ -63,79 +64,43 @@ Via npm: $ npm install [-g] shelljs ``` -If the global option `-g` is specified, the binary `shjs` will be installed. This makes it possible to -run ShellJS scripts much like any shell script from the command line, i.e. without requiring a `node_modules` folder: - -```bash -$ shjs my_script -``` - ## Examples -### JavaScript - ```javascript -require('shelljs/global'); +var shell = require('shelljs'); -if (!which('git')) { - echo('Sorry, this script requires git'); - exit(1); +if (!shell.which('git')) { + shell.echo('Sorry, this script requires git'); + shell.exit(1); } // Copy files to release dir -rm('-rf', 'out/Release'); -cp('-R', 'stuff/', 'out/Release'); +shell.rm('-rf', 'out/Release'); +shell.cp('-R', 'stuff/', 'out/Release'); // Replace macros in each .js file -cd('lib'); -ls('*.js').forEach(function(file) { - sed('-i', 'BUILD_VERSION', 'v0.1.2', file); - sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file); - sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file); +shell.cd('lib'); +shell.ls('*.js').forEach(function (file) { + shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file); + shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file); + shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file); }); -cd('..'); +shell.cd('..'); // Run external tool synchronously -if (exec('git commit -am "Auto-commit"').code !== 0) { - echo('Error: Git commit failed'); - exit(1); +if (shell.exec('git commit -am "Auto-commit"').code !== 0) { + shell.echo('Error: Git commit failed'); + shell.exit(1); } ``` -### CoffeeScript - -CoffeeScript is also supported automatically: - -```coffeescript -require 'shelljs/global' - -if not which 'git' - echo 'Sorry, this script requires git' - exit 1 - -# Copy files to release dir -rm '-rf', 'out/Release' -cp '-R', 'stuff/', 'out/Release' - -# Replace macros in each .js file -cd 'lib' -for file in ls '*.js' - sed '-i', 'BUILD_VERSION', 'v0.1.2', file - sed '-i', /^.*REMOVE_THIS_LINE.*$/, '', file - sed '-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file -cd '..' - -# Run external tool synchronously -if (exec 'git commit -am "Auto-commit"').code != 0 - echo 'Error: Git commit failed' - exit 1 -``` - ## Global vs. Local -The example above uses the convenience script `shelljs/global` to reduce verbosity. If polluting your global namespace is not desirable, simply require `shelljs`. +We no longer recommend using a global-import for ShellJS (i.e. +`require('shelljs/global')`). While still supported for convenience, this +pollutes the global namespace, and should therefore only be used with caution. -Example: +Instead, we recommend a local import (standard for npm packages): ```javascript var shell = require('shelljs'); @@ -311,7 +276,7 @@ Available options (all `false` by default): + `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. -+ and any option available to NodeJS's ++ 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) Examples: @@ -814,6 +779,6 @@ Reset shell.config to the defaults: ## Team -| [![Nate Fischer](https://avatars.githubusercontent.com/u/5801521?s=130)](https://github.com/nfischer) | [![Ari Porad](https://avatars1.githubusercontent.com/u/1817508?v=3&s=130)](http://github.com/ariporad) | +| [![Nate Fischer](https://avatars.githubusercontent.com/u/5801521?s=130)](https://github.com/nfischer) | [![Brandon Freitag](https://avatars1.githubusercontent.com/u/5988055?v=3&s=130)](http://github.com/freitagbr) | |:---:|:---:| -| [Nate Fischer](https://github.com/nfischer) | [Ari Porad](http://github.com/ariporad) | +| [Nate Fischer](https://github.com/nfischer) | [Brandon Freitag](http://github.com/freitagbr) | diff --git a/src/exec.js b/src/exec.js index aade0228c..5d360e868 100644 --- a/src/exec.js +++ b/src/exec.js @@ -228,7 +228,7 @@ function execAsync(cmd, opts, pipe, callback) { //@ + `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. -//@ + and any option available to NodeJS's +//@ + 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) //@ //@ Examples: From eb5230a53c997cde3c74043f926c0f51de62d7fb Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 4 Mar 2017 17:53:37 -0800 Subject: [PATCH 015/108] chore: add codecov (#682) * chore: add codecov Add codecov to ShellJS Partial fix for #671 * Add codecov badge to README --- .travis.yml | 2 ++ README.md | 1 + package.json | 1 + 3 files changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 49666f084..afd8f5603 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,8 @@ script: # make sure when the docs are generated nothing changes (a.k.a. the docs have already been generated) - npm run gendocs - npm run after-travis "Make sure to generate docs!" +after_success: + - codecov # Gitter notifications: diff --git a/README.md b/README.md index e8d8a0100..91f110ff4 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![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) [![npm version](https://img.shields.io/npm/v/shelljs.svg?style=flat-square)](https://www.npmjs.com/package/shelljs) [![npm downloads](https://img.shields.io/npm/dm/shelljs.svg?style=flat-square)](https://www.npmjs.com/package/shelljs) diff --git a/package.json b/package.json index 950d695fe..e7194c734 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ }, "devDependencies": { "ava": "^0.16.0", + "codecov": "^1.0.1", "coffee-script": "^1.10.0", "eslint": "^2.0.0", "eslint-config-airbnb-base": "^3.0.0", From 346fca4cb62a01c1d00a5a7d3485b170fe24d143 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 4 Mar 2017 17:54:43 -0800 Subject: [PATCH 016/108] test: don't count hard-to-test lines for coverage (#672) No change in logic. Add `/* istanbul ignore next */` lines for hard-to-test lines so that they don't count against us during code coverage. I've also adjusted comments that I found confusing, and changed some formatting. Partial fix for #671 --- src/common.js | 4 ++++ src/cp.js | 3 +++ src/mkdir.js | 1 + src/mv.js | 10 +++++++--- src/rm.js | 6 +++++- src/tempdir.js | 1 + src/test.js | 3 +++ src/to.js | 1 + src/toEnd.js | 1 + 9 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/common.js b/src/common.js index 8b07421a9..d8d403a3f 100644 --- a/src/common.js +++ b/src/common.js @@ -73,6 +73,7 @@ exports.platform = platform; var pipeMethods = []; function log() { + /* istanbul ignore next */ if (!config.silent) { console.error.apply(console, arguments); } @@ -259,6 +260,7 @@ function unlinkSync(file) { fs.unlinkSync(file); } catch (e) { // Try to override file permission + /* istanbul ignore next */ if (e.code === 'EPERM') { fs.chmodSync(file, '0666'); fs.unlinkSync(file); @@ -364,6 +366,7 @@ function wrap(cmd, fn, options) { retValue = fn.apply(this, args); } catch (e) { + /* istanbul ignore else */ if (e.msg === 'earlyExit') { retValue = e.retValue; } else { @@ -372,6 +375,7 @@ function wrap(cmd, fn, options) { } } } catch (e) { + /* 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'); diff --git a/src/cp.js b/src/cp.js index 111e031c9..d1f56334b 100644 --- a/src/cp.js +++ b/src/cp.js @@ -54,12 +54,14 @@ function copyFileSync(srcFile, destFile, options) { try { fdr = fs.openSync(srcFile, 'r'); } catch (e) { + /* istanbul ignore next */ common.error('copyFileSync: could not read src file (' + srcFile + ')'); } try { fdw = fs.openSync(destFile, 'w'); } catch (e) { + /* istanbul ignore next */ common.error('copyFileSync: could not write to dest file (code=' + e.code + '):' + destFile); } @@ -243,6 +245,7 @@ function _cp(options, sources, dest) { fs.statSync(path.dirname(dest)); cpdirSyncRecursive(src, newDest, 0, { no_force: options.no_force, followsymlink: options.followsymlink }); } catch (e) { + /* istanbul ignore next */ common.error("cannot create directory '" + dest + "': No such file or directory"); } } diff --git a/src/mkdir.js b/src/mkdir.js index 0b8c6fe53..115f75ca4 100644 --- a/src/mkdir.js +++ b/src/mkdir.js @@ -83,6 +83,7 @@ function _mkdir(options, dirs) { if (e.code === 'EACCES') { common.error('cannot create directory ' + dir + ': Permission denied'); } else { + /* istanbul ignore next */ throw e; } } diff --git a/src/mv.js b/src/mv.js index c09bbbc76..7fc7cf04c 100644 --- a/src/mv.js +++ b/src/mv.js @@ -38,6 +38,7 @@ function _mv(options, sources, dest) { } else if (typeof sources === 'string') { sources = [sources]; } else { + // TODO(nate): figure out if we actually need this line common.error('invalid arguments'); } @@ -82,9 +83,12 @@ function _mv(options, sources, dest) { try { fs.renameSync(src, thisDest); } catch (e) { - if (e.code === 'EXDEV') { // external partition - // if either of these fails, the appropriate error message will bubble - // up to the top level automatically + /* istanbul ignore next */ + if (e.code === 'EXDEV') { + // If we're trying to `mv` to an external partition, we'll actually need + // to perform a copy and then clean up the original file. If either the + // copy or the rm fails with an exception, we should allow this + // exception to pass up to the top level. cp('-r', src, thisDest); rm('-rf', src); } diff --git a/src/rm.js b/src/rm.js index 803adbc5e..6ce6719a4 100644 --- a/src/rm.js +++ b/src/rm.js @@ -34,7 +34,10 @@ function rmdirSyncRecursive(dir, force) { try { common.unlinkSync(file); } catch (e) { - common.error('could not remove file (code ' + e.code + '): ' + file, { continue: true }); + /* istanbul ignore next */ + common.error('could not remove file (code ' + e.code + '): ' + file, { + continue: true, + }); } } } @@ -55,6 +58,7 @@ function rmdirSyncRecursive(dir, force) { if (fs.existsSync(dir)) throw { code: 'EAGAIN' }; break; } catch (er) { + /* istanbul ignore next */ // In addition to error codes, also check if the directory still exists and loop again if true if (process.platform === 'win32' && (er.code === 'ENOTEMPTY' || er.code === 'EBUSY' || er.code === 'EPERM' || er.code === 'EAGAIN')) { if (Date.now() - start > 1000) throw er; diff --git a/src/tempdir.js b/src/tempdir.js index cfd56b379..a2d15be36 100644 --- a/src/tempdir.js +++ b/src/tempdir.js @@ -19,6 +19,7 @@ function writeableDir(dir) { common.unlinkSync(testFile); return dir; } catch (e) { + /* istanbul ignore next */ return false; } } diff --git a/src/test.js b/src/test.js index 3fb38aec4..d3d9c07a0 100644 --- a/src/test.js +++ b/src/test.js @@ -72,10 +72,13 @@ function _test(options, path) { if (options.file) return stats.isFile(); + /* istanbul ignore next */ if (options.pipe) return stats.isFIFO(); + /* istanbul ignore next */ if (options.socket) return stats.isSocket(); + /* istanbul ignore next */ return false; // fallback } // test module.exports = _test; diff --git a/src/to.js b/src/to.js index 99f194e68..d3d9e37be 100644 --- a/src/to.js +++ b/src/to.js @@ -30,6 +30,7 @@ function _to(options, file) { fs.writeFileSync(file, this.stdout || this.toString(), 'utf8'); return this; } catch (e) { + /* istanbul ignore next */ common.error('could not write to file (code ' + e.code + '): ' + file, { continue: true }); } } diff --git a/src/toEnd.js b/src/toEnd.js index cf91c9401..dc165fe8d 100644 --- a/src/toEnd.js +++ b/src/toEnd.js @@ -29,6 +29,7 @@ function _toEnd(options, file) { fs.appendFileSync(file, this.stdout || this.toString(), 'utf8'); return this; } catch (e) { + /* istanbul ignore next */ common.error('could not append to file (code ' + e.code + '): ' + file, { continue: true }); } } From 35016ce1e7cb2a9be4ba3d5ea141cb89a9eae2d2 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sun, 5 Mar 2017 02:28:47 -0800 Subject: [PATCH 017/108] test: add misc. tests to improve coverage (#673) No change in production logic. This adds missing tests to improve test coverage. This does not change ShellJS behavior at all--all test cases are testing already-working functionality. One test case has been renamed for clarity. For the "omit directory if missing recursive flag" case, we were actually already testing that in another case, but we were testing multiple things in that test case. It's better to test this one error condition explicitly in its own case. When adding real tests for `parseOptions()`, we need to explicitly clear `common.state.error` because we're testing an internal function, not a wrapped command. Partial fix for #671 --- test/common.js | 25 +++++++++++++++++++++++++ test/cp.js | 37 ++++++++++++++++++++++++++++++++++++- test/mv.js | 21 ++++++++++++--------- test/rm.js | 7 +++++++ test/toEnd.js | 6 ++++++ 5 files changed, 86 insertions(+), 10 deletions(-) diff --git a/test/common.js b/test/common.js index 2bb4a7600..bc2c4da89 100644 --- a/test/common.js +++ b/test/common.js @@ -6,6 +6,11 @@ import utils from './utils/utils'; shell.config.silent = true; +test.beforeEach(() => { + common.state.error = null; + common.state.errorCode = 0; +}); + // // Invalids // @@ -22,6 +27,26 @@ test('should be a list', t => { }, TypeError); }); +test('parseOptions (invalid option in options object)', t => { + t.throws(() => { + common.parseOptions({ q: 'some string value' }, { + R: 'recursive', + f: 'force', + r: 'reverse', + }); + }); +}); + +test('parseOptions (invalid type)', t => { + t.throws(() => { + common.parseOptions(12, { + R: 'recursive', + f: 'force', + r: 'reverse', + }); + }); +}); + // // Valids // diff --git a/test/cp.js b/test/cp.js index 4cb16e500..74c8dd836 100644 --- a/test/cp.js +++ b/test/cp.js @@ -71,7 +71,7 @@ test('source does not exist', t => { t.is(result.stderr, 'cp: no such file or directory: asdfasdf'); }); -test('sources does not exist', t => { +test('multiple sources do not exist', t => { const result = shell.cp('asdfasdf1', 'asdfasdf2', t.context.tmp); t.truthy(shell.error()); t.is(result.code, 1); @@ -112,6 +112,32 @@ test('dest already exists', t => { t.is(shell.cat('resources/file2').toString(), oldContents); }); +test('-nR does not overwrite an existing file at the destination', t => { + // Create tmp/new/cp/a + const dest = `${t.context.tmp}/new/cp`; + shell.mkdir('-p', dest); + 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/`); + t.falsy(shell.error()); + t.is(result.code, 0); + t.falsy(result.stderr); + t.is(shell.cat(`${dest}/a`).toString(), oldContents); +}); + +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}`); + new common.ShellString(oldContents).to(`${t.context.tmp}/file1`); + const result = shell.cp('-n', 'resources/file1', `${t.context.tmp}`); + t.falsy(shell.error()); + t.is(result.code, 0); + t.falsy(result.stderr); + t.is(shell.cat(`${t.context.tmp}/file1`).toString(), oldContents); +}); + test('-f by default', t => { shell.cp('resources/file2', 'resources/copyfile2'); const result = shell.cp('resources/file1', 'resources/file2'); // dest already exists @@ -215,6 +241,15 @@ test('recursive, with regular files', t => { t.truthy(fs.existsSync(`${t.context.tmp}/file2`)); }); +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'"); + 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); t.falsy(shell.error()); diff --git a/test/mv.js b/test/mv.js index dcf1e22f2..9d3fbaf92 100644 --- a/test/mv.js +++ b/test/mv.js @@ -91,6 +91,15 @@ test('-n is no-force/no-clobber', t => { t.is(result.stderr, 'mv: dest file already exists: file2'); }); +test('-n option with a directory as the destination', t => { + shell.cp('file1', 'cp'); // copy it so we're sure it's already there + const result = shell.mv('-n', 'file1', 'cp'); + t.truthy(shell.error()); + t.is(result.code, 1); + // TODO(nate): make this an equals comparison once issue #681 is resolved + t.regex(result.stderr, /mv: dest file already exists: cp.file1/); +}); + test('-f is the default behavior', t => { const result = shell.mv('file1', 'file2'); // dest already exists (but that's ok) t.falsy(shell.error()); @@ -153,19 +162,13 @@ test('one source', t => { }); test('two sources', t => { - shell.rm('-rf', 't'); - shell.mkdir('-p', 't'); - let result = shell.mv('file1', 'file2', 't'); + const result = shell.mv('file1', 'file2', 'cp'); t.falsy(shell.error()); t.is(result.code, 0); t.falsy(fs.existsSync('file1')); t.falsy(fs.existsSync('file2')); - t.truthy(fs.existsSync('t/file1')); - t.truthy(fs.existsSync('t/file2')); - result = shell.mv('t/*', '.'); // revert - t.is(result.code, 0); - t.truthy(fs.existsSync('file1')); - t.truthy(fs.existsSync('file2')); + t.truthy(fs.existsSync('cp/file1')); + t.truthy(fs.existsSync('cp/file2')); }); test('two sources, array style', t => { diff --git a/test/rm.js b/test/rm.js index cdb3e925f..1d88a882f 100644 --- a/test/rm.js +++ b/test/rm.js @@ -35,6 +35,13 @@ test('file does not exist', t => { t.is(result.stderr, 'rm: no such file or directory: asdfasdf'); }); +test('cannot delete a directoy without recursive flag', t => { + const result = shell.rm(`${t.context.tmp}/rm`); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, 'rm: path is a directory'); +}); + test('only an option', t => { const result = shell.rm('-f'); t.truthy(shell.error()); diff --git a/test/toEnd.js b/test/toEnd.js index 323e4a857..cdb7fb68c 100644 --- a/test/toEnd.js +++ b/test/toEnd.js @@ -30,6 +30,12 @@ test('missing file argument', t => { t.truthy(shell.error()); }); +test('cannot write to a non-existent directory', t => { + t.falsy(fs.existsSync('/asdfasdf')); // sanity check + shell.ShellString('hello world').toEnd('/asdfasdf/file'); + t.truthy(shell.error()); +}); + // // Valids // From 7a94b1bbba2417439d2416c2ec27aa70feb85f36 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sun, 5 Mar 2017 10:24:09 -0800 Subject: [PATCH 018/108] Refactor tests to improve readability (#685) No change in production logic. --- test/common.js | 2 +- test/ls.js | 28 ++++++++++++++++++---------- test/pipe.js | 4 ++-- test/to.js | 2 +- test/toEnd.js | 2 +- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/test/common.js b/test/common.js index bc2c4da89..f53b3d7d5 100644 --- a/test/common.js +++ b/test/common.js @@ -143,7 +143,7 @@ test('Some basic tests on the ShellString type', t => { const result = shell.ShellString('foo'); t.is(result.toString(), 'foo'); t.is(result.stdout, 'foo'); - t.is(typeof result.stderr, 'undefined'); + t.is(result.stderr, undefined); t.truthy(result.to); t.truthy(result.toEnd); }); diff --git a/test/ls.js b/test/ls.js index 4285ea0a6..89497039e 100644 --- a/test/ls.js +++ b/test/ls.js @@ -382,8 +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 - t.truthy(process.platform === 'win32' || result.uid); // only on unix - t.truthy(process.platform === 'win32' || result.gid); // only on unix + if (process.platform !== 'win32') { + 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 @@ -399,8 +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 - t.truthy(process.platform === 'win32' || result.uid); // only on unix - t.truthy(process.platform === 'win32' || result.gid); // only on unix + if (process.platform !== 'win32') { + 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 @@ -419,8 +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 - t.truthy(process.platform === 'win32' || result.uid); // only on unix - t.truthy(process.platform === 'win32' || result.gid); // only on unix + if (process.platform !== 'win32') { + 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 @@ -437,11 +443,13 @@ test('long option, directory, recursive (and windows converts slashes)', t => { result = result[idx]; t.is(result.name, result.name); t.truthy(fs.statSync('resources/ls/a_dir/b_dir').isDirectory()); - t.truthy(typeof result.nlink === 'number'); // This can vary between the local machine and travis - t.truthy(typeof result.size === 'number'); // This can vary between different file systems + 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 - t.truthy(process.platform === 'win32' || result.uid); // only on unix - t.truthy(process.platform === 'win32' || result.gid); // only on unix + if (process.platform !== 'win32') { + 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/pipe.js b/test/pipe.js index dbb2cc5fd..cc71e0cf0 100644 --- a/test/pipe.js +++ b/test/pipe.js @@ -9,8 +9,8 @@ shell.config.silent = true; // test('commands like `rm` cannot be on the right side of pipes', t => { - t.is(typeof shell.ls('.').rm, 'undefined'); - t.is(typeof shell.cat('resources/file1.txt').rm, 'undefined'); + t.is(shell.ls('.').rm, undefined); + t.is(shell.cat('resources/file1.txt').rm, undefined); }); // diff --git a/test/to.js b/test/to.js index db3ce2450..9774b8331 100644 --- a/test/to.js +++ b/test/to.js @@ -22,7 +22,7 @@ test.afterEach.always(t => { test('Normal strings don\'t have \'.to()\' anymore', t => { const str = 'hello world'; - t.is(typeof str.to, 'undefined'); + t.is(str.to, undefined); }); test('no file argument', t => { diff --git a/test/toEnd.js b/test/toEnd.js index cdb7fb68c..cf3aec4f9 100644 --- a/test/toEnd.js +++ b/test/toEnd.js @@ -22,7 +22,7 @@ test.afterEach.always(t => { test('Normal strings don\'t have \'.toEnd()\' anymore', t => { const str = 'hello world'; - t.is(typeof str.toEnd, 'undefined'); + t.is(str.toEnd, undefined); }); test('missing file argument', t => { From fb09c6aab88dfe193e5eb5fdb1d05f622029d919 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sun, 5 Mar 2017 10:25:44 -0800 Subject: [PATCH 019/108] chore: add codecov script to appveyor CI (#686) Invoke codecov on appveyor builds too, so that we can get coverage for Windows-specific lines of code. Partial fix for #671 --- appveyor.yml | 3 +++ package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index bbde9e705..a081ad22e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,3 +24,6 @@ build: off test_script: - npm test + +on_success: + - npm run codecov -- -f coverage/lcov.info diff --git a/package.json b/package.json index e7194c734..01633f8fe 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "lint": "eslint .", "after-travis": "travis-check-changes", "changelog": "shelljs-changelog", + "codecov": "codecov", "release:major": "shelljs-release major", "release:minor": "shelljs-release minor", "release:patch": "shelljs-release patch" From b6b2cd84ef7ece7d3ebec21957eb23c51c034908 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 6 Mar 2017 00:54:26 -0800 Subject: [PATCH 020/108] fix: convert error output to be consistent cross-platform (#684) * fix: convert error output to be consistent cross-platform The error output produced by `shell.error()` or `result.stderr` should not be inconsistent between platforms. This ensures that path separators are always printed by ShellJS as `/` instead of as `\` on Windows. This should allow scripts using ShellJS to be more consistent cross-platform. We were not previously relying on error output to always be consistent-- only checking its truthiness. Since this was not part of our tested API, it should be reasonable to change this and release in a patch. Fixes #681 * Fix broken pushd test case * Fix TODO in a test case --- src/common.js | 13 ++++++++++++- test/common.js | 40 ++++++++++++++++++++++++++++++++++++++++ test/mv.js | 3 +-- test/pushd.js | 3 ++- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/common.js b/src/common.js index d8d403a3f..cc8274a20 100644 --- a/src/common.js +++ b/src/common.js @@ -80,6 +80,17 @@ function log() { } exports.log = log; +// Converts strings to be equivalent across all platforms. Primarily responsible +// for making sure we use '/' instead of '\' as path separators, but this may be +// expanded in the future if necessary +function convertErrorOutput(msg) { + if (typeof msg !== 'string') { + throw new TypeError('input must be a string'); + } + return msg.replace(/\\/g, '/'); +} +exports.convertErrorOutput = convertErrorOutput; + // Shows error message. Throws if config.fatal is true function error(msg, _code, options) { // Validate input @@ -105,7 +116,7 @@ function error(msg, _code, options) { if (!state.errorCode) state.errorCode = options.code; - var logEntry = options.prefix + msg; + var logEntry = convertErrorOutput(options.prefix + msg); state.error = state.error ? state.error + '\n' : ''; state.error += logEntry; diff --git a/test/common.js b/test/common.js index f53b3d7d5..1bbcbd7e9 100644 --- a/test/common.js +++ b/test/common.js @@ -47,10 +47,50 @@ test('parseOptions (invalid type)', t => { }); }); +test('convertErrorOutput: no args', t => { + t.throws(() => { + common.convertErrorOutput(); + }, TypeError); +}); + +test('convertErrorOutput: input must be a vanilla string', t => { + t.throws(() => { + common.convertErrorOutput(3); + }, TypeError); + + t.throws(() => { + common.convertErrorOutput({}); + }, TypeError); +}); + // // Valids // +// +// common.convertErrorOutput() +// +test('convertErrorOutput: nothing to convert', t => { + const input = 'hello world'; + const result = common.convertErrorOutput(input); + t.is(result, input); +}); + +test('convertErrorOutput: does not change forward slash', t => { + const input = 'dir/sub/file.txt'; + const result = common.convertErrorOutput(input); + t.is(result, input); +}); + +test('convertErrorOutput: changes backslashes to forward slashes', t => { + const input = 'dir\\sub\\file.txt'; + const result = common.convertErrorOutput(input); + t.is(result, 'dir/sub/file.txt'); +}); + +// +// common.expand() +// test('single file, array syntax', t => { const result = common.expand(['resources/file1.txt']); t.falsy(shell.error()); diff --git a/test/mv.js b/test/mv.js index 9d3fbaf92..9bf1bb954 100644 --- a/test/mv.js +++ b/test/mv.js @@ -96,8 +96,7 @@ test('-n option with a directory as the destination', t => { const result = shell.mv('-n', 'file1', 'cp'); t.truthy(shell.error()); t.is(result.code, 1); - // TODO(nate): make this an equals comparison once issue #681 is resolved - t.regex(result.stderr, /mv: dest file already exists: cp.file1/); + t.is(result.stderr, 'mv: dest file already exists: cp/file1'); }); test('-f is the default behavior', t => { diff --git a/test/pushd.js b/test/pushd.js index 96bfe47ee..68d266849 100644 --- a/test/pushd.js +++ b/test/pushd.js @@ -273,7 +273,8 @@ test('Push invalid directory', t => { shell.pushd('does/not/exist'); t.is( shell.error(), - 'pushd: no such file or directory: ' + path.resolve('.', 'does/not/exist') + `pushd: no such file or directory: ${path.resolve('.', 'does/not/exist') + .replace(/\\/g, '/')}` ); t.is(process.cwd(), oldCwd); }); From 5b5a28d2de28859f835f9dbc704c5aa636462184 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Tue, 7 Mar 2017 22:18:43 -0800 Subject: [PATCH 021/108] Fix cp overwriting identical files (#679) * Implement fix for cp with identical files * Implement tests for cp with identical files * Change error message * Use common.error immediately if the file is identical * Add test for copying to exact same path --- src/cp.js | 7 +++++++ test/cp.js | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/cp.js b/src/cp.js index d1f56334b..04c4e57ef 100644 --- a/src/cp.js +++ b/src/cp.js @@ -263,9 +263,16 @@ function _cp(options, sources, dest) { return; // skip file } + if (path.relative(src, thisDest) === '') { + // a file cannot be copied to itself, but we want to continue copying other files + common.error("'" + thisDest + "' and '" + src + "' are the same file", { continue: true }); + return; + } + copyFileSync(src, thisDest, options); } }); // forEach(src) + return new common.ShellString('', common.state.error, common.state.errorCode); } module.exports = _cp; diff --git a/test/cp.js b/test/cp.js index 74c8dd836..76525f09a 100644 --- a/test/cp.js +++ b/test/cp.js @@ -688,3 +688,28 @@ test('recursive, with a non-normalized path', t => { t.falsy(result.stderr); t.is(result.code, 0); }); + +test('copy file to same path', t => { + const result = shell.cp('resources/file1', '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"); +}); + +test('copy file to same directory', t => { + const result = shell.cp('resources/file1', 'resources'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, "cp: 'resources/file1' and 'resources/file1' are the same file"); +}); + +test('copy mutliple files to same location', t => { + const result = shell.cp('resources/file1', 'resources/file2', '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" + ); +}); From 79497594633b4af663e7b137350b841de0ed5343 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Wed, 8 Mar 2017 07:33:41 -0800 Subject: [PATCH 022/108] Add support for removing fifos (#687) * Add support for removing fifos in rm * Add test for removing fifo * Add mkfifo util for testing * Use ES5 syntax in utils --- src/rm.js | 2 +- test/rm.js | 9 +++++++++ test/utils/utils.js | 10 ++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/rm.js b/src/rm.js index 6ce6719a4..595368114 100644 --- a/src/rm.js +++ b/src/rm.js @@ -141,7 +141,7 @@ function _rm(options, files) { } else { common.error('path is a directory', { continue: true }); } - } else if (stats.isSymbolicLink()) { + } else if (stats.isSymbolicLink() || stats.isFIFO()) { common.unlinkSync(file); } }); // forEach(file) diff --git a/test/rm.js b/test/rm.js index 1d88a882f..5156edd6c 100644 --- a/test/rm.js +++ b/test/rm.js @@ -298,3 +298,12 @@ test('recursive dir removal, for non-normalized path', t => { t.is(result.code, 0); t.falsy(fs.existsSync(`${t.context.tmp}/a`)); }); + +test('remove fifo', t => { + if (process.platform !== 'win32') { + 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/utils/utils.js b/test/utils/utils.js index 814f82b87..a1d313143 100644 --- a/test/utils/utils.js +++ b/test/utils/utils.js @@ -36,3 +36,13 @@ function sleep(time) { child.execFileSync(common.config.execPath, ['resources/exec/slow.js', time.toString()]); } exports.sleep = sleep; + +function mkfifo(dir) { + if (process.platform !== 'win32') { + const fifo = dir + 'fifo'; + child.execFileSync('mkfifo', [fifo]); + return fifo; + } + return null; +} +exports.mkfifo = mkfifo; From 54c1befe94fe4d5bc4c912590d3e4ab63594d624 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Wed, 8 Mar 2017 19:30:56 -0800 Subject: [PATCH 023/108] refactor(parseOptions): better handle errors (#674) * refactor(parseOptions): better handle errors For the case where `parseOptions()` is passed a string that does not start with a hyphen, we should reject this string instead of returning the same value. This has no change on any other test cases, and should not affect any commands since we are careful about what input we pass to `parseOptions()` This also adjust how we were handling error cases in the function. We were previously using two different calls to `common.error()`, one for if `errorOptions` is passed, and one without. This hurts readability, because it reads like "if we have errorOptions, then this is an error, and if we don't then it's also an error," instead of the more appropriate, "we reached an error case and should use errorOptions if it's available, otherwise we should signal an error without using it." We do not need to use `errorOptions` for the added call to `error()`, since this is an error which indicates misuse, and should not be recoverable. This adds a test case as well, for a line which was not previously covered in our tests. Partial fix for #671 * Refactor parseOptions() This validates input at the top of `parseOptions()` for type correctness. This changes `typeof x === 'object'` to `x instanceOf Object` to improve robustness. Now we can safely use `errorOptions` knowing that if it has a truthy value, it will be an object, otherwise we should use defaults instead. The new tests ensure that we have 100% unit test coverage for this function. * Use exceptions, not common.error()s, for internal misuse * Add common.isObject() helper function The `isObject()` helper is used throughout common.js to reliably test if variables are JavaScript objects. --- src/common.js | 53 +++++++++++++++++++++++++++----------------------- test/common.js | 46 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 24 deletions(-) diff --git a/src/common.js b/src/common.js index cc8274a20..f5197d8ec 100644 --- a/src/common.js +++ b/src/common.js @@ -72,6 +72,12 @@ exports.platform = platform; // 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; +} +exports.isObject = isObject; + function log() { /* istanbul ignore next */ if (!config.silent) { @@ -103,9 +109,9 @@ function error(msg, _code, options) { silent: false, }; - if (typeof _code === 'number' && typeof options === 'object') { + if (typeof _code === 'number' && isObject(options)) { options.code = _code; - } else if (typeof _code === 'object') { // no 'code' + } else if (isObject(_code)) { // no 'code' options = _code; } else if (typeof _code === 'number') { // no 'options' options = { code: _code }; @@ -184,22 +190,29 @@ exports.getUserHome = getUserHome; // Returns {'reference': 'string-value', 'bob': false} when passed two dictionaries of the form: // parseOptions({'-r': 'string-value'}, {'r':'reference', 'b':'bob'}); function parseOptions(opt, map, errorOptions) { - if (!map) error('parseOptions() internal error: no map given'); + // Validate input + if (typeof opt !== 'string' && !isObject(opt)) { + throw new Error('options must be strings or key-value pairs'); + } else if (!isObject(map)) { + throw new Error('parseOptions() internal error: map must be an object'); + } else if (errorOptions && !isObject(errorOptions)) { + throw new Error('parseOptions() internal error: errorOptions must be object'); + } // All options are false by default var options = {}; Object.keys(map).forEach(function (letter) { - if (map[letter][0] !== '!') { - options[map[letter]] = false; + var optName = map[letter]; + if (optName[0] !== '!') { + options[optName] = false; } }); - if (!opt) return options; // defaults + if (opt === '') return options; // defaults - var optionName; if (typeof opt === 'string') { if (opt[0] !== '-') { - return options; + error("Options string must start with a '-'", errorOptions || {}); } // e.g. chars = ['R', 'f'] @@ -207,35 +220,27 @@ function parseOptions(opt, map, errorOptions) { chars.forEach(function (c) { if (c in map) { - optionName = map[c]; + var optionName = map[c]; if (optionName[0] === '!') { options[optionName.slice(1)] = false; } else { options[optionName] = true; } - } else if (typeof errorOptions === 'object') { - error('option not recognized: ' + c, errorOptions); } else { - error('option not recognized: ' + c); + error('option not recognized: ' + c, errorOptions || {}); } }); - } else if (typeof opt === 'object') { + } else { // opt is an Object Object.keys(opt).forEach(function (key) { // key is a string of the form '-r', '-d', etc. var c = key[1]; if (c in map) { - optionName = map[c]; + var optionName = map[c]; options[optionName] = opt[key]; // assign the given value - } else if (typeof errorOptions === 'object') { - error('option not recognized: ' + c, errorOptions); } else { - error('option not recognized: ' + c); + error('option not recognized: ' + c, errorOptions || {}); } }); - } else if (typeof errorOptions === 'object') { - error('options must be strings or key-value pairs', errorOptions); - } else { - error('options must be strings or key-value pairs'); } return options; } @@ -328,7 +333,7 @@ function wrap(cmd, fn, options) { if (options.unix === false) { // this branch is for exec() retValue = fn.apply(this, args); } else { // and this branch is for everything else - if (args[0] instanceof Object && args[0].constructor.name === 'Object') { + if (isObject(args[0]) && args[0].constructor.name === 'Object') { // a no-op, allowing the syntax `touch({'-r': file}, ...)` } else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') { args.unshift(''); // only add dummy option if '-option' not already present @@ -348,7 +353,7 @@ function wrap(cmd, fn, options) { // Convert ShellStrings (basically just String objects) to regular strings args = args.map(function (arg) { - if (arg instanceof Object && arg.constructor.name === 'String') { + if (isObject(arg) && arg.constructor.name === 'String') { return arg.toString(); } return arg; @@ -371,7 +376,7 @@ function wrap(cmd, fn, options) { try { // parse options if options are provided - if (typeof options.cmdOptions === 'object') { + if (isObject(options.cmdOptions)) { args[0] = parseOptions(args[0], options.cmdOptions); } diff --git a/test/common.js b/test/common.js index 1bbcbd7e9..fb3103bf8 100644 --- a/test/common.js +++ b/test/common.js @@ -37,6 +37,52 @@ test('parseOptions (invalid option in options object)', t => { }); }); +test('parseOptions (without a hyphen in the string)', t => { + t.throws(() => { + common.parseOptions('f', { + f: 'force', + }); + }); +}); + +test('parseOptions (opt is not a string/object)', t => { + t.throws(() => { + common.parseOptions(1, { + f: 'force', + }); + }); +}); + +test('parseOptions (map is not an object)', t => { + t.throws(() => { + common.parseOptions('-f', 27); + }); +}); + +test('parseOptions (errorOptions is not an object)', t => { + t.throws(() => { + common.parseOptions('-f', { + f: 'force', + }, 'not a valid errorOptions'); + }); +}); + +test('parseOptions (unrecognized string option)', t => { + t.throws(() => { + common.parseOptions('-z', { + f: 'force', + }); + }); +}); + +test('parseOptions (unrecognized option in Object)', t => { + t.throws(() => { + common.parseOptions({ '-c': 7 }, { + f: 'force', + }); + }); +}); + test('parseOptions (invalid type)', t => { t.throws(() => { common.parseOptions(12, { From 95638cc773390920a446e383c40ed8104c7d211d Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Wed, 8 Mar 2017 22:37:03 -0800 Subject: [PATCH 024/108] 0.7.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 01633f8fe..fb1c75428 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.7.6", + "version": "0.7.7", "description": "Portable Unix shell commands for Node.js", "keywords": [ "shelljs", From b9201eba0f0032940bcfb987a59de84c74e561c3 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Wed, 8 Mar 2017 22:38:36 -0800 Subject: [PATCH 025/108] docs(changelog): updated by Nate Fischer [ci skip] --- CHANGELOG.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e66d72cf9..6de319e18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,52 @@ # Change Log +## [v0.7.7](https://github.com/shelljs/shelljs/tree/v0.7.7) (2017-03-09) +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.6...v0.7.7) + +**Closed issues:** + +- Error output should be consistent across all platforms. [\#681](https://github.com/shelljs/shelljs/issues/681) +- \*CRITICAL data loss\* shell.cp\(\) Content of file is erased when trying to copy it to the folder it already belongs to [\#678](https://github.com/shelljs/shelljs/issues/678) +- Use with webpack broken in 0.7.6 [\#667](https://github.com/shelljs/shelljs/issues/667) +- 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) +- 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) + +**Merged pull requests:** + +- Add support for removing fifos [\#687](https://github.com/shelljs/shelljs/pull/687) ([freitagbr](https://github.com/freitagbr)) +- chore: add codecov script to appveyor CI [\#686](https://github.com/shelljs/shelljs/pull/686) ([nfischer](https://github.com/nfischer)) +- Refactor tests to improve readability [\#685](https://github.com/shelljs/shelljs/pull/685) ([nfischer](https://github.com/nfischer)) +- fix: convert error output to be consistent cross-platform [\#684](https://github.com/shelljs/shelljs/pull/684) ([nfischer](https://github.com/nfischer)) +- chore: add codecov [\#682](https://github.com/shelljs/shelljs/pull/682) ([nfischer](https://github.com/nfischer)) +- Fix cp overwriting identical files [\#679](https://github.com/shelljs/shelljs/pull/679) ([freitagbr](https://github.com/freitagbr)) +- Modified glob pattern. Fixes \#666 [\#676](https://github.com/shelljs/shelljs/pull/676) ([frandiox](https://github.com/frandiox)) +- refactor\(parseOptions\): better handle errors [\#674](https://github.com/shelljs/shelljs/pull/674) ([nfischer](https://github.com/nfischer)) +- test: add misc. tests to improve coverage [\#673](https://github.com/shelljs/shelljs/pull/673) ([nfischer](https://github.com/nfischer)) +- test: don't count hard-to-test lines for coverage [\#672](https://github.com/shelljs/shelljs/pull/672) ([nfischer](https://github.com/nfischer)) +- fix: switch commands.json -\> commands.js [\#668](https://github.com/shelljs/shelljs/pull/668) ([nfischer](https://github.com/nfischer)) +- ls -L \(follow symlinks\) [\#665](https://github.com/shelljs/shelljs/pull/665) ([frandiox](https://github.com/frandiox)) +- docs\(chmod\): document `options` argument [\#663](https://github.com/shelljs/shelljs/pull/663) ([gkalpak](https://github.com/gkalpak)) +- docs: clean up RELEASE.md [\#662](https://github.com/shelljs/shelljs/pull/662) ([nfischer](https://github.com/nfischer)) +- docs: miscellaneous README changes [\#661](https://github.com/shelljs/shelljs/pull/661) ([nfischer](https://github.com/nfischer)) +- Fix typo in README [\#660](https://github.com/shelljs/shelljs/pull/660) ([faheel](https://github.com/faheel)) +- refactor: reduce repeated code in which\(\) [\#659](https://github.com/shelljs/shelljs/pull/659) ([nfischer](https://github.com/nfischer)) +- feature: add -a option for which command [\#655](https://github.com/shelljs/shelljs/pull/655) ([termosa](https://github.com/termosa)) +- Fix find ENOENT [\#654](https://github.com/shelljs/shelljs/pull/654) ([freitagbr](https://github.com/freitagbr)) +- Safely exit by throwing an error [\#649](https://github.com/shelljs/shelljs/pull/649) ([freitagbr](https://github.com/freitagbr)) +- Chore drop 0.12 [\#648](https://github.com/shelljs/shelljs/pull/648) ([nfischer](https://github.com/nfischer)) +- chore\(lint\): Enforce a trailing comma for multi-line [\#646](https://github.com/shelljs/shelljs/pull/646) ([nfischer](https://github.com/nfischer)) +- docs\(release\): use bulleted list [\#643](https://github.com/shelljs/shelljs/pull/643) ([freitagbr](https://github.com/freitagbr)) + ## [v0.7.6](https://github.com/shelljs/shelljs/tree/v0.7.6) (2017-01-08) [Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.5...v0.7.6) @@ -553,8 +600,8 @@ **Merged pull requests:** -- Addition of a toEnd\(\) function modeled after the Unix \>\> pipe. [\#78](https://github.com/shelljs/shelljs/pull/78) ([andreweduffy](https://github.com/andreweduffy)) -- Added appendTo\(\) function to imitate '\>\>' redirect-and-append pipe. [\#75](https://github.com/shelljs/shelljs/pull/75) ([andreweduffy](https://github.com/andreweduffy)) +- Addition of a toEnd\(\) function modeled after the Unix \>\> pipe. [\#78](https://github.com/shelljs/shelljs/pull/78) ([a10y](https://github.com/a10y)) +- Added appendTo\(\) function to imitate '\>\>' redirect-and-append pipe. [\#75](https://github.com/shelljs/shelljs/pull/75) ([a10y](https://github.com/a10y)) - Fix a small typo in README.md [\#71](https://github.com/shelljs/shelljs/pull/71) ([asmblah](https://github.com/asmblah)) - adding an `.npmignore` file [\#70](https://github.com/shelljs/shelljs/pull/70) ([stephenmathieson](https://github.com/stephenmathieson)) - tempdir: use `os.tmpDir` when possible [\#67](https://github.com/shelljs/shelljs/pull/67) ([stephenmathieson](https://github.com/stephenmathieson)) From 80d590ec0575e1dc8a83268f8fedd310c7c7e43d Mon Sep 17 00:00:00 2001 From: Christian Zommerfelds Date: Thu, 30 Mar 2017 23:30:30 -0400 Subject: [PATCH 026/108] Small clarification of verbose flag (#691) * small clarification of verbose flag * nfischer's documentation suggestion * verbose flag documentation in source file --- README.md | 6 ++++-- shell.js | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 91f110ff4..1f3e6ec0f 100644 --- a/README.md +++ b/README.md @@ -732,14 +732,16 @@ Example: ```javascript config.verbose = true; // or set('-v'); cd('dir/'); -ls('subdir/'); +rm('-rf', 'foo.txt', 'bar.txt'); +exec('echo hello'); ``` Will print each command as follows: ``` cd dir/ -ls subdir/ +rm -rf foo.txt bar.txt +exec echo hello ``` ### config.globOptions diff --git a/shell.js b/shell.js index f155f3d3a..2541a2036 100644 --- a/shell.js +++ b/shell.js @@ -103,14 +103,16 @@ exports.config = common.config; //@ ```javascript //@ config.verbose = true; // or set('-v'); //@ cd('dir/'); -//@ ls('subdir/'); +//@ rm('-rf', 'foo.txt', 'bar.txt'); +//@ exec('echo hello'); //@ ``` //@ //@ Will print each command as follows: //@ //@ ``` //@ cd dir/ -//@ ls subdir/ +//@ rm -rf foo.txt bar.txt +//@ exec echo hello //@ ``` //@ From e12da9d888c03b0b7cc6c75bcf9a3251fa2322fd Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Fri, 14 Apr 2017 23:04:21 -0700 Subject: [PATCH 027/108] Refactor: Use process.platform across codebase (#689) * Use process.platform across codebase * Use process.platform in tests --- src/common.js | 3 --- src/cp.js | 11 +++++++---- src/find.js | 2 +- src/ln.js | 2 +- src/which.js | 5 +++-- test/cp.js | 2 +- test/test.js | 11 +++++------ 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/common.js b/src/common.js index f5197d8ec..e0d343b8c 100644 --- a/src/common.js +++ b/src/common.js @@ -66,9 +66,6 @@ exports.state = state; delete process.env.OLDPWD; // initially, there's no previous directory -var platform = os.type().match(/^Win/) ? 'win' : 'unix'; -exports.platform = platform; - // This is populated by calls to commonl.wrap() var pipeMethods = []; diff --git a/src/cp.js b/src/cp.js index 04c4e57ef..52af77be0 100644 --- a/src/cp.js +++ b/src/cp.js @@ -1,7 +1,6 @@ var fs = require('fs'); var path = require('path'); var common = require('./common'); -var os = require('os'); common.register('cp', _cp, { cmdOptions: { @@ -24,6 +23,8 @@ function copyFileSync(srcFile, destFile, options) { common.error('copyFileSync: no such file or directory: ' + srcFile); } + var isWindows = process.platform === 'win32'; + // Check the mtimes of the files if the '-u' flag is provided try { if (options.update && fs.statSync(srcFile).mtime < fs.statSync(destFile).mtime) { @@ -42,7 +43,7 @@ function copyFileSync(srcFile, destFile, options) { } var symlinkFull = fs.readlinkSync(srcFile); - fs.symlinkSync(symlinkFull, destFile, os.platform() === 'win32' ? 'junction' : null); + fs.symlinkSync(symlinkFull, destFile, isWindows ? 'junction' : null); } else { var BUF_LENGTH = 64 * 1024; var buf = new Buffer(BUF_LENGTH); @@ -93,6 +94,8 @@ function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { if (currentDepth >= common.config.maxdepth) return; currentDepth++; + var isWindows = process.platform === 'win32'; + // Create the directory where all our junk is moving to; read the mode of the // source directory and mirror it try { @@ -116,7 +119,7 @@ function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { // Cycle link found. console.error('Cycle link found.'); symlinkFull = fs.readlinkSync(srcFile); - fs.symlinkSync(symlinkFull, destFile, os.platform() === 'win32' ? 'junction' : null); + fs.symlinkSync(symlinkFull, destFile, isWindows ? 'junction' : null); continue; } } @@ -131,7 +134,7 @@ function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { } catch (e) { // it doesn't exist, so no work needs to be done } - fs.symlinkSync(symlinkFull, destFile, os.platform() === 'win32' ? 'junction' : null); + fs.symlinkSync(symlinkFull, destFile, isWindows ? 'junction' : null); } else if (srcFileStat.isSymbolicLink() && opts.followsymlink) { srcFileStat = fs.statSync(srcFile); if (srcFileStat.isDirectory()) { diff --git a/src/find.js b/src/find.js index 625aa2972..76a16c4ee 100644 --- a/src/find.js +++ b/src/find.js @@ -30,7 +30,7 @@ function _find(options, paths) { var list = []; function pushFile(file) { - if (common.platform === 'win') { + if (process.platform === 'win32') { file = file.replace(/\\/g, '/'); } list.push(file); diff --git a/src/ln.js b/src/ln.js index 7393d9fcd..9b8beb9ec 100644 --- a/src/ln.js +++ b/src/ln.js @@ -43,7 +43,7 @@ function _ln(options, source, dest) { } if (options.symlink) { - var isWindows = common.platform === 'win'; + var isWindows = process.platform === 'win32'; var linkType = isWindows ? 'file' : null; var resolvedSourcePath = isAbsolute ? sourcePath : path.resolve(process.cwd(), path.dirname(dest), source); if (!fs.existsSync(resolvedSourcePath)) { diff --git a/src/which.js b/src/which.js index 03db57bcd..a5f9e15eb 100644 --- a/src/which.js +++ b/src/which.js @@ -37,6 +37,7 @@ 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); @@ -47,7 +48,7 @@ function _which(options, cmd) { // Assume that there are no extensions to append to queries (this is the // case for unix) var pathExtArray = ['']; - if (common.platform === 'win') { + if (isWindows) { // In case the PATHEXT variable is somehow not set (e.g. // child_process.spawn with an empty environment), use the XP default. var pathExtEnv = process.env.PATHEXT || XP_DEFAULT_PATHEXT; @@ -61,7 +62,7 @@ function _which(options, cmd) { var attempt = path.resolve(pathArray[k], cmd); - if (common.platform === 'win') { + if (isWindows) { attempt = attempt.toUpperCase(); } diff --git a/test/cp.js b/test/cp.js index 76525f09a..94f0e23a2 100644 --- a/test/cp.js +++ b/test/cp.js @@ -405,7 +405,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 (common.platform !== 'win') { + if (process.platform !== 'win32') { // preserve mode bits const execBit = parseInt('001', 8); t.is(fs.statSync('resources/cp-mode-bits/executable').mode & execBit, execBit); diff --git a/test/test.js b/test/test.js index 498bbea6d..39f25795e 100644 --- a/test/test.js +++ b/test/test.js @@ -1,7 +1,6 @@ import test from 'ava'; import shell from '..'; -import common from '../src/common'; shell.config.silent = true; @@ -91,7 +90,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 => { - if (common.platform !== 'win') { + if (process.platform !== 'win32') { const result = shell.test('-d', 'resources/link'); t.falsy(shell.error()); t.falsy(result); @@ -99,7 +98,7 @@ test('-d option fails for a link', t => { }); test('-f option succeeds for a link', t => { - if (common.platform !== 'win') { + if (process.platform !== 'win32') { const result = shell.test('-f', 'resources/link'); t.falsy(shell.error()); t.truthy(result); @@ -107,7 +106,7 @@ test('-f option succeeds for a link', t => { }); test('-L option succeeds for a symlink', t => { - if (common.platform !== 'win') { + if (process.platform !== 'win32') { const result = shell.test('-L', 'resources/link'); t.falsy(shell.error()); t.truthy(result); @@ -115,7 +114,7 @@ test('-L option succeeds for a symlink', t => { }); test('-L option works for broken symlinks', t => { - if (common.platform !== 'win') { + if (process.platform !== 'win32') { const result = shell.test('-L', 'resources/badlink'); t.falsy(shell.error()); t.truthy(result); @@ -123,7 +122,7 @@ test('-L option works for broken symlinks', t => { }); test('-L option fails for missing files', t => { - if (common.platform !== 'win') { + if (process.platform !== 'win32') { const result = shell.test('-L', 'resources/404'); t.falsy(shell.error()); t.falsy(result); From 7feabda0d65e18324d16c1657351568ab26b6626 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Sat, 15 Apr 2017 00:49:10 -0700 Subject: [PATCH 028/108] Remove contents of symlink to dir with rm -rf (#688) * rm -rf on a symlink to a dir deletes contents * Fix comment typo * Clarify comments * Pass symlink directly to rmdirSync * Skip rm -rf symlink test on windows --- src/rm.js | 88 ++++++++++++++++++++++++++++++++++++++++++------------ test/rm.js | 21 ++++++------- 2 files changed, 80 insertions(+), 29 deletions(-) diff --git a/src/rm.js b/src/rm.js index 595368114..2ad6914b4 100644 --- a/src/rm.js +++ b/src/rm.js @@ -17,7 +17,7 @@ common.register('rm', _rm, { // // Licensed under the MIT License // http://www.opensource.org/licenses/mit-license.php -function rmdirSyncRecursive(dir, force) { +function rmdirSyncRecursive(dir, force, fromSymlink) { var files; files = fs.readdirSync(dir); @@ -43,6 +43,10 @@ function rmdirSyncRecursive(dir, force) { } } + // if was directory was referenced through a symbolic link, + // the contents should be removed, but not the directory itself + if (fromSymlink) return; + // Now that we know everything in the sub-tree has been deleted, we can delete the main directory. // Huzzah for the shopkeep. @@ -91,6 +95,57 @@ function isWriteable(file) { return writePermission; } +function handleFile(file, options) { + if (options.force || isWriteable(file)) { + // -f was passed, or file is writable, so it can be removed + common.unlinkSync(file); + } else { + common.error('permission denied: ' + file, { continue: true }); + } +} + +function handleDirectory(file, options) { + if (options.recursive) { + // -r was passed, so directory can be removed + rmdirSyncRecursive(file, options.force); + } else { + common.error('path is a directory', { continue: true }); + } +} + +function handleSymbolicLink(file, options) { + var stats; + try { + stats = fs.statSync(file); + } catch (e) { + // symlink is broken, so remove the symlink itself + common.unlinkSync(file); + return; + } + + if (stats.isFile()) { + common.unlinkSync(file); + } else if (stats.isDirectory()) { + if (file[file.length - 1] === '/') { + // trailing separator, so remove the contents, not the link + if (options.recursive) { + // -r was passed, so directory can be removed + var fromSymlink = true; + rmdirSyncRecursive(file, options.force, fromSymlink); + } else { + common.error('path is a directory', { continue: true }); + } + } else { + // no trailing separator, so remove the link + common.unlinkSync(file); + } + } +} + +function handleFIFO(file) { + common.unlinkSync(file); +} + //@ //@ ### rm([options,] file [, file ...]) //@ ### rm([options,] file_array) @@ -115,9 +170,12 @@ function _rm(options, files) { files = [].slice.call(arguments, 1); files.forEach(function (file) { - var stats; + var lstats; try { - stats = fs.lstatSync(file); // test for existence + 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 } catch (e) { // Path does not exist, no force flag given if (!options.force) { @@ -127,22 +185,14 @@ function _rm(options, files) { } // If here, path exists - if (stats.isFile()) { - if (options.force || isWriteable(file)) { - // -f was passed, or file is writable, so it can be removed - common.unlinkSync(file); - } else { - common.error('permission denied: ' + file, { continue: true }); - } - } else if (stats.isDirectory()) { - if (options.recursive) { - // -r was passed, so directory can be removed - rmdirSyncRecursive(file, options.force); - } else { - common.error('path is a directory', { continue: true }); - } - } else if (stats.isSymbolicLink() || stats.isFIFO()) { - common.unlinkSync(file); + if (lstats.isFile()) { + handleFile(file, options); + } else if (lstats.isDirectory()) { + handleDirectory(file, options); + } else if (lstats.isSymbolicLink()) { + handleSymbolicLink(file, options); + } else if (lstats.isFIFO()) { + handleFIFO(file); } }); // forEach(file) return ''; diff --git a/test/rm.js b/test/rm.js index 5156edd6c..e729d2d13 100644 --- a/test/rm.js +++ b/test/rm.js @@ -150,7 +150,7 @@ test('recursive dir removal', t => { t.is(result.code, 0); const contents = fs.readdirSync(t.context.tmp); t.is(contents.length, 1); - t.is(contents[0], '.hidden'); // shouldn't remove hiddden if no .* given + t.is(contents[0], '.hidden'); // shouldn't remove hidden if no .* given }); test('recursive dir removal #2', t => { @@ -267,16 +267,17 @@ test('remove symbolic link to a dir', t => { t.truthy(fs.existsSync(`${t.context.tmp}/rm/a_dir`)); }); -// TODO(nfischer): fix this behavior in rm -test.skip('rm -rf on a symbolic link to a dir deletes its contents', t => { - const result = shell.rm('-rf', `${t.context.tmp}/rm/link_to_a_dir/`); - t.falsy(shell.error()); - t.is(result.code, 0); +test('rm -rf on a symbolic link to a dir deletes its contents', t => { + if (process.platform !== 'win32') { + const result = shell.rm('-rf', `${t.context.tmp}/rm/link_to_a_dir/`); + t.falsy(shell.error()); + t.is(result.code, 0); - // Both the link and original dir should remain, but contents are deleted - 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`)); + // Both the link and original dir should remain, but contents are deleted + 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 => { From d8ac4d3f028a3ae09e5632dfbcf8bfa9580af50f Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Sat, 15 Apr 2017 00:51:29 -0700 Subject: [PATCH 029/108] refactor: remove unnecessary common.js imports (#703) No change in logic. This removes unnecessary imports of `common.js` in favor of the `shell` package. --- test/common.js | 10 +++++----- test/cp.js | 3 +-- test/exec.js | 31 +++++++++++++++---------------- test/set.js | 11 +++++------ test/shjs.js | 3 +-- 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/test/common.js b/test/common.js index fb3103bf8..68051b7c6 100644 --- a/test/common.js +++ b/test/common.js @@ -248,11 +248,11 @@ test.cb('Commands that fail will still output error messages to stderr', t => { test('execPath value makes sense', t => { // TODO(nate): change this test if we add electron support in the unit tests - t.is(common.config.execPath, process.execPath); - t.is(typeof common.config.execPath, 'string'); + t.is(shell.config.execPath, process.execPath); + t.is(typeof shell.config.execPath, 'string'); }); -test('Changing common.config.execPath does not modify process', t => { - common.config.execPath = 'foo'; - t.not(common.config.execPath, process.execPath); +test('Changing shell.config.execPath does not modify process', t => { + shell.config.execPath = 'foo'; + t.not(shell.config.execPath, process.execPath); }); diff --git a/test/cp.js b/test/cp.js index 94f0e23a2..8b5b98d33 100644 --- a/test/cp.js +++ b/test/cp.js @@ -3,7 +3,6 @@ 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; @@ -130,7 +129,7 @@ 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}`); - new common.ShellString(oldContents).to(`${t.context.tmp}/file1`); + new shell.ShellString(oldContents).to(`${t.context.tmp}/file1`); const result = shell.cp('-n', 'resources/file1', `${t.context.tmp}`); t.falsy(shell.error()); t.is(result.code, 0); diff --git a/test/exec.js b/test/exec.js index bf41d7a08..7110e34f9 100644 --- a/test/exec.js +++ b/test/exec.js @@ -5,15 +5,14 @@ import util from 'util'; import test from 'ava'; import shell from '..'; -import common from '../src/common'; const CWD = process.cwd(); -const ORIG_EXEC_PATH = common.config.execPath; +const ORIG_EXEC_PATH = shell.config.execPath; shell.config.silent = true; test.afterEach.always(() => { process.chdir(CWD); - common.config.execPath = ORIG_EXEC_PATH; + shell.config.execPath = ORIG_EXEC_PATH; }); // @@ -40,7 +39,7 @@ test('config.fatal and unknown command', t => { }); test('exec exits gracefully if we cannot find the execPath', t => { - common.config.execPath = null; + shell.config.execPath = null; shell.exec('echo foo'); t.regex( shell.error(), @@ -57,14 +56,14 @@ test('exec exits gracefully if we cannot find the execPath', t => { // test('check if stdout goes to output', t => { - const result = shell.exec(`${JSON.stringify(common.config.execPath)} -e "console.log(1234);"`); + const result = shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.log(1234);"`); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.stdout, '1234\n'); }); test('check if stderr goes to output', t => { - const result = shell.exec(`${JSON.stringify(common.config.execPath)} -e "console.error(1234);"`); + const result = shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.error(1234);"`); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.stdout, ''); @@ -72,7 +71,7 @@ test('check if stderr goes to output', t => { }); test('check if stdout + stderr go to output', t => { - const result = shell.exec(`${JSON.stringify(common.config.execPath)} -e "console.error(1234); console.log(666);"`); + const result = shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.error(1234); console.log(666);"`); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.stdout, '666\n'); @@ -80,21 +79,21 @@ test('check if stdout + stderr go to output', t => { }); test('check exit code', t => { - const result = shell.exec(`${JSON.stringify(common.config.execPath)} -e "process.exit(12);"`); + const result = shell.exec(`${JSON.stringify(shell.config.execPath)} -e "process.exit(12);"`); t.truthy(shell.error()); t.is(result.code, 12); }); test('interaction with cd', t => { shell.cd('resources/external'); - const result = shell.exec(`${JSON.stringify(common.config.execPath)} node_script.js`); + const result = shell.exec(`${JSON.stringify(shell.config.execPath)} node_script.js`); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.stdout, 'node_script_1234\n'); }); test('check quotes escaping', t => { - const result = shell.exec(util.format(JSON.stringify(common.config.execPath) + ' -e "console.log(%s);"', "\\\"\\'+\\'_\\'+\\'\\\"")); + const result = shell.exec(util.format(JSON.stringify(shell.config.execPath) + ' -e "console.log(%s);"', "\\\"\\'+\\'_\\'+\\'\\\"")); t.falsy(shell.error()); t.is(result.code, 0); t.is(result.stdout, "'+'_'+'\n"); @@ -120,12 +119,12 @@ test('set maxBuffer (very small)', t => { }); test('set timeout option', t => { - const result = shell.exec(`${JSON.stringify(common.config.execPath)} resources/exec/slow.js 100`); // default timeout is ok + const result = shell.exec(`${JSON.stringify(shell.config.execPath)} 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(common.config.execPath)} resources/exec/slow.js 100`, { timeout: 10 }); // times out + shell.exec(`${JSON.stringify(shell.config.execPath)} resources/exec/slow.js 100`, { timeout: 10 }); // times out t.truthy(shell.error()); } @@ -171,14 +170,14 @@ test('exec returns a ShellString', t => { // test.cb('no callback', t => { - const c = shell.exec(`${JSON.stringify(common.config.execPath)} -e "console.log(1234)"`, { async: true }); + const c = shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.log(1234)"`, { async: true }); t.falsy(shell.error()); t.truthy('stdout' in c, 'async exec returns child process object'); t.end(); }); test.cb('callback as 2nd argument', t => { - shell.exec(`${JSON.stringify(common.config.execPath)} -e "console.log(5678);"`, (code, stdout, stderr) => { + shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.log(5678);"`, (code, stdout, stderr) => { t.is(code, 0); t.is(stdout, '5678\n'); t.is(stderr, ''); @@ -187,7 +186,7 @@ test.cb('callback as 2nd argument', t => { }); test.cb('callback as end argument', t => { - shell.exec(`${JSON.stringify(common.config.execPath)} -e "console.log(5566);"`, { async: true }, (code, stdout, stderr) => { + shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.log(5566);"`, { async: true }, (code, stdout, stderr) => { t.is(code, 0); t.is(stdout, '5566\n'); t.is(stderr, ''); @@ -196,7 +195,7 @@ test.cb('callback as end argument', t => { }); test.cb('callback as 3rd argument (silent:true)', t => { - shell.exec(`${JSON.stringify(common.config.execPath)} -e "console.log(5678);"`, { silent: true }, (code, stdout, stderr) => { + shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.log(5678);"`, { silent: true }, (code, stdout, stderr) => { t.is(code, 0); t.is(stdout, '5678\n'); t.is(stderr, ''); diff --git a/test/set.js b/test/set.js index 446d52ed8..957e168d9 100644 --- a/test/set.js +++ b/test/set.js @@ -1,7 +1,6 @@ import test from 'ava'; import shell from '..'; -import common from '../src/common'; import utils from './utils/utils'; const oldConfigSilent = shell.config.silent; @@ -29,21 +28,21 @@ test('initial values', t => { }); test('default behavior', t => { - const result = shell.exec(JSON.stringify(common.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(common.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(common.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( @@ -53,7 +52,7 @@ test('set -v', t => { }); test('set -ev', t => { - const result = shell.exec(JSON.stringify(common.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); @@ -62,7 +61,7 @@ test('set -ev', t => { }); test('set -e, set +e', t => { - const result = shell.exec(JSON.stringify(common.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/shjs.js b/test/shjs.js index 9a4221a5d..4df91666d 100644 --- a/test/shjs.js +++ b/test/shjs.js @@ -3,13 +3,12 @@ import path from 'path'; import test from 'ava'; import shell from '..'; -import common from '../src/common'; 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(common.config.execPath)} ` + ? `${JSON.stringify(shell.config.execPath)} ` : ''; const script = path.resolve(__dirname, 'resources', 'shjs', name); return shell.exec(`${execPath}${binPath} ${script}`, { silent: true }); From bbe521b57dfeda64954bc9a4eff99890fa85cce4 Mon Sep 17 00:00:00 2001 From: Kumar Uttpal Date: Sat, 15 Apr 2017 14:31:58 +0530 Subject: [PATCH 030/108] Fix #631 throw error when overwriting recently created file (#702) * cp: add error to not overwrite recently created files #631 * cp: add tests for errors not overwrite recently created files #631 * mv: show error when overwriting recently created file #631 * mv: add tests for error on recently created files #631 * mv: test remove unnecessary steps #631 --- src/cp.js | 21 +++++++++++++++++++-- src/mv.js | 20 +++++++++++++++++++- test/cp.js | 36 ++++++++++++++++++++++++++++++++++++ test/mv.js | 27 +++++++++++++++++++++++++++ test/resources/cp/file1 | 1 + 5 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 test/resources/cp/file1 diff --git a/src/cp.js b/src/cp.js index 52af77be0..25b895e06 100644 --- a/src/cp.js +++ b/src/cp.js @@ -153,6 +153,14 @@ function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { } // for files } // cpdirSyncRecursive +// Checks if cureent file was created recently +function checkRecentCreated(sources, index) { + var lookedSource = sources[index]; + return sources.slice(0, index).some(function (src) { + return path.basename(src) === path.basename(lookedSource); + }); +} + function cpcheckcycle(sourceDir, srcFile) { var srcFileStat = fs.lstatSync(srcFile); if (srcFileStat.isSymbolicLink()) { @@ -227,7 +235,7 @@ function _cp(options, sources, dest) { return new common.ShellString('', '', 0); } - sources.forEach(function (src) { + sources.forEach(function (src, srcIndex) { if (!fs.existsSync(src)) { common.error('no such file or directory: ' + src, { continue: true }); return; // skip file @@ -262,7 +270,16 @@ function _cp(options, sources, dest) { thisDest = path.normalize(dest + '/' + path.basename(src)); } - if (fs.existsSync(thisDest) && options.no_force) { + var thisDestExists = fs.existsSync(thisDest); + if (thisDestExists && checkRecentCreated(sources, srcIndex)) { + // cannot overwrite file created recently in current execution, but we want to continue copying other files + if (!options.no_force) { + common.error("will not overwrite just-created '" + thisDest + "' with '" + src + "'", { continue: true }); + } + return; + } + + if (thisDestExists && options.no_force) { return; // skip file } diff --git a/src/mv.js b/src/mv.js index 7fc7cf04c..6ebaa8a03 100644 --- a/src/mv.js +++ b/src/mv.js @@ -11,6 +11,14 @@ common.register('mv', _mv, { }, }); +// Checks if cureent file was created recently +function checkRecentCreated(sources, index) { + var lookedSource = sources[index]; + return sources.slice(0, index).some(function (src) { + return path.basename(src) === path.basename(lookedSource); + }); +} + //@ //@ ### mv([options ,] source [, source ...], dest') //@ ### mv([options ,] source_array, dest') @@ -55,7 +63,7 @@ function _mv(options, sources, dest) { common.error('dest file already exists: ' + dest); } - sources.forEach(function (src) { + sources.forEach(function (src, srcIndex) { if (!fs.existsSync(src)) { common.error('no such file or directory: ' + src, { continue: true }); return; // skip file @@ -70,6 +78,16 @@ function _mv(options, sources, dest) { thisDest = path.normalize(dest + '/' + path.basename(src)); } + var thisDestExists = fs.existsSync(thisDest); + + if (thisDestExists && checkRecentCreated(sources, srcIndex)) { + // cannot overwrite file created recently in current execution, but we want to continue copying other files + if (!options.no_force) { + common.error("will not overwrite just-created '" + thisDest + "' with '" + src + "'", { continue: true }); + } + return; + } + if (fs.existsSync(thisDest) && options.no_force) { common.error('dest file already exists: ' + thisDest, { continue: true }); return; // skip file diff --git a/test/cp.js b/test/cp.js index 8b5b98d33..d8ec03462 100644 --- a/test/cp.js +++ b/test/cp.js @@ -712,3 +712,39 @@ test('copy mutliple files to same location', t => { "cp: 'resources/file2' and '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); + t.truthy(shell.error()); + t.is(result.code, 1); + + // Ensure First file is copied + 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'` + ); +}); + + +test('should not overwrite recently created files (in recursive Mode)', t => { + const result = shell.cp('-R', 'resources/file1', 'resources/cp/file1', t.context.tmp); + t.truthy(shell.error()); + t.is(result.code, 1); + + // Ensure First file is copied + 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'` + ); +}); + +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); + t.falsy(shell.error()); + t.is(result.code, 0); + + // Ensure First file is copied + t.is(shell.cat(`${t.context.tmp}/file1`).toString(), 'test1'); +}); diff --git a/test/mv.js b/test/mv.js index 9bf1bb954..32bc80ef8 100644 --- a/test/mv.js +++ b/test/mv.js @@ -206,3 +206,30 @@ test('dest exists, but -f given', t => { t.falsy(fs.existsSync('file1')); t.truthy(fs.existsSync('file2')); }); + +test('should not overwrite recently created files', t => { + shell.mkdir('-p', 't'); + const result = shell.mv('file1', 'cp/file1', 't/'); + t.truthy(shell.error()); + t.is(result.code, 1); + + // Ensure First file is copied + t.is(shell.cat('t/file1').toString(), 'test1'); + t.is( + result.stderr, + "mv: will not overwrite just-created 't/file1' with 'cp/file1'" + ); + t.truthy(fs.existsSync('cp/file1')); +}); + + +test('should not overwrite recently created files (not give error no-force mode)', t => { + shell.mkdir('-p', 't'); + const result = shell.mv('-n', 'file1', 'cp/file1', 't/'); + t.falsy(shell.error()); + t.is(result.code, 0); + + // Ensure First file is moved + t.is(shell.cat('t/file1').toString(), 'test1'); + t.truthy(fs.existsSync('cp/file1')); +}); diff --git a/test/resources/cp/file1 b/test/resources/cp/file1 new file mode 100644 index 000000000..180cf8328 --- /dev/null +++ b/test/resources/cp/file1 @@ -0,0 +1 @@ +test2 From 92d3f3982e05b6c6f69ebef08858ee6ceebc8eaf Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Tue, 2 May 2017 19:54:56 -0700 Subject: [PATCH 031/108] Fix common.expand error (#709) * When glob.sync errors, return original array element * Add test for cp with empty string --- src/common.js | 13 ++++++++++--- src/cp.js | 1 + test/common.js | 18 ++++++++++++++++++ test/cp.js | 7 +++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/common.js b/src/common.js index e0d343b8c..30b166dd2 100644 --- a/src/common.js +++ b/src/common.js @@ -257,9 +257,16 @@ function expand(list) { if (typeof listEl !== 'string') { expanded.push(listEl); } else { - var ret = glob.sync(listEl, config.globOptions); - // if glob fails, interpret the string literally - expanded = expanded.concat(ret.length > 0 ? ret : [listEl]); + var ret; + try { + ret = glob.sync(listEl, config.globOptions); + // if nothing matched, interpret the string literally + ret = ret.length > 0 ? ret : [listEl]; + } catch (e) { + // if glob fails, interpret the string literally + ret = [listEl]; + } + expanded = expanded.concat(ret); } }); return expanded; diff --git a/src/cp.js b/src/cp.js index 25b895e06..500df2ba7 100644 --- a/src/cp.js +++ b/src/cp.js @@ -237,6 +237,7 @@ function _cp(options, sources, dest) { sources.forEach(function (src, srcIndex) { if (!fs.existsSync(src)) { + if (src === '') src = "''"; // if src was empty string, display empty string common.error('no such file or directory: ' + src, { continue: true }); return; // skip file } diff --git a/test/common.js b/test/common.js index 68051b7c6..024af6f9e 100644 --- a/test/common.js +++ b/test/common.js @@ -170,6 +170,24 @@ test('broken links still expand', t => { t.deepEqual(result, ['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]); +}); + test('common.parseOptions (normal case)', t => { const result = common.parseOptions('-Rf', { R: 'recursive', diff --git a/test/cp.js b/test/cp.js index d8ec03462..e8cece026 100644 --- a/test/cp.js +++ b/test/cp.js @@ -98,6 +98,13 @@ test('too many sources #2', t => { t.is(result.stderr, 'cp: dest is not a directory (too many sources)'); }); +test('empty string source', t => { + const result = shell.cp('', 'dest'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, "cp: no such file or directory: ''"); +}); + // // Valids // From 951ff22671b90032b653ee7ccac21e226919ee15 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Tue, 2 May 2017 23:04:56 -0700 Subject: [PATCH 032/108] Add common.buffer (#710) * Add common.buffer * Fix comment --- src/common.js | 12 ++++++++++++ src/cp.js | 10 +++++----- src/head.js | 10 +++++----- test/common.js | 26 ++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/common.js b/src/common.js index 30b166dd2..4a1f43456 100644 --- a/src/common.js +++ b/src/common.js @@ -38,6 +38,7 @@ var DEFAULT_CONFIG = { silent: false, verbose: false, execPath: null, + bufLength: 64 * 1024, // 64KB }; var config = { @@ -273,6 +274,17 @@ function expand(list) { } exports.expand = expand; +// Normalizes Buffer creation, using Buffer.alloc if possible. +// Also provides a good default buffer length for most use cases. +var buffer = typeof Buffer.alloc === 'function' ? + function (len) { + return Buffer.alloc(len || config.bufLength); + } : + function (len) { + return new Buffer(len || config.bufLength); + }; +exports.buffer = buffer; + // Normalizes _unlinkSync() across platforms to match Unix behavior, i.e. // file can be unlinked even if it's read-only, see https://github.com/joyent/node/issues/3006 function unlinkSync(file) { diff --git a/src/cp.js b/src/cp.js index 500df2ba7..99c97b2eb 100644 --- a/src/cp.js +++ b/src/cp.js @@ -45,9 +45,9 @@ function copyFileSync(srcFile, destFile, options) { var symlinkFull = fs.readlinkSync(srcFile); fs.symlinkSync(symlinkFull, destFile, isWindows ? 'junction' : null); } else { - var BUF_LENGTH = 64 * 1024; - var buf = new Buffer(BUF_LENGTH); - var bytesRead = BUF_LENGTH; + var buf = common.buffer(); + var bufLength = buf.length; + var bytesRead = bufLength; var pos = 0; var fdr = null; var fdw = null; @@ -66,8 +66,8 @@ function copyFileSync(srcFile, destFile, options) { common.error('copyFileSync: could not write to dest file (code=' + e.code + '):' + destFile); } - while (bytesRead === BUF_LENGTH) { - bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos); + while (bytesRead === bufLength) { + bytesRead = fs.readSync(fdr, buf, 0, bufLength, pos); fs.writeSync(fdw, buf, 0, bytesRead); pos += bytesRead; } diff --git a/src/head.js b/src/head.js index 13d582977..db5592e76 100644 --- a/src/head.js +++ b/src/head.js @@ -10,9 +10,9 @@ common.register('head', _head, { // This reads n or more lines, or the entire file, whichever is less. function readSomeLines(file, numLines) { - var BUF_LENGTH = 64 * 1024; - var buf = new Buffer(BUF_LENGTH); - var bytesRead = BUF_LENGTH; + var buf = common.buffer(); + var bufLength = buf.length; + var bytesRead = bufLength; var pos = 0; var fdr = null; @@ -24,8 +24,8 @@ function readSomeLines(file, numLines) { var numLinesRead = 0; var ret = ''; - while (bytesRead === BUF_LENGTH && numLinesRead < numLines) { - bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos); + while (bytesRead === bufLength && numLinesRead < numLines) { + bytesRead = fs.readSync(fdr, buf, 0, bufLength, pos); var bufStr = buf.toString('utf8', 0, bytesRead); numLinesRead += bufStr.split('\n').length - 1; ret += bufStr; diff --git a/test/common.js b/test/common.js index 024af6f9e..a6f1e9f52 100644 --- a/test/common.js +++ b/test/common.js @@ -188,6 +188,32 @@ test('non-string', t => { t.deepEqual(result, [5]); }); +// +// common.buffer() +// +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); +}); + +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(); +}); + test('common.parseOptions (normal case)', t => { const result = common.parseOptions('-Rf', { R: 'recursive', From a2e13b62dce776f7a3de7ad05d466cf24f4e5248 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 8 May 2017 22:57:58 -0700 Subject: [PATCH 033/108] Properly handle directories as arguments (#713) * fix(cat): do not cat directories Fixes #707 * fix(head): do not let head() read directories Also fixes a typo * fix(sort): do not sort directories Also fixes a typo * fix(tail): do not let tail() read directories Also fixes a typo * fix(uniq): do not let uniq() read directories We also had a test which called sort() instead of uniq(), so we never actually tested the missing-file case. This fixes that as well. This also throws an error for using a directory as output. * fix(pipe): fix breakages with piped commands --- src/cat.js | 2 ++ src/head.js | 13 ++++++++++--- src/sort.js | 13 ++++++++++--- src/tail.js | 13 ++++++++++--- src/uniq.js | 13 ++++++++++++- test/cat.js | 7 +++++++ test/head.js | 11 ++++++++++- test/sort.js | 10 +++++++++- test/tail.js | 10 +++++++++- test/uniq.js | 25 ++++++++++++++++++++++++- 10 files changed, 103 insertions(+), 14 deletions(-) diff --git a/src/cat.js b/src/cat.js index a74a25c84..af1ad1d4d 100644 --- a/src/cat.js +++ b/src/cat.js @@ -30,6 +30,8 @@ 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()) { + common.error(file + ': Is a directory'); } cat += fs.readFileSync(file, 'utf8'); diff --git a/src/head.js b/src/head.js index db5592e76..e112e49e1 100644 --- a/src/head.js +++ b/src/head.js @@ -72,9 +72,16 @@ function _head(options, files) { var shouldAppendNewline = false; files.forEach(function (file) { - if (!fs.existsSync(file) && file !== '-') { - common.error('no such file or directory: ' + file, { continue: true }); - return; + if (file !== '-') { + if (!fs.existsSync(file)) { + common.error('no such file or directory: ' + file, { continue: true }); + return; + } else if (fs.statSync(file).isDirectory()) { + common.error("error reading '" + file + "': Is a directory", { + continue: true, + }); + return; + } } var contents; diff --git a/src/sort.js b/src/sort.js index 041b03772..2ebccd7f4 100644 --- a/src/sort.js +++ b/src/sort.js @@ -69,9 +69,16 @@ function _sort(options, files) { var lines = []; files.forEach(function (file) { - if (!fs.existsSync(file) && file !== '-') { - // exit upon any sort of error - common.error('no such file or directory: ' + file); + if (file !== '-') { + if (!fs.existsSync(file)) { + common.error('no such file or directory: ' + file, { continue: true }); + return; + } else if (fs.statSync(file).isDirectory()) { + common.error('read failed: ' + file + ': Is a directory', { + continue: true, + }); + return; + } } var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); diff --git a/src/tail.js b/src/tail.js index 7ece654b1..e5a88055c 100644 --- a/src/tail.js +++ b/src/tail.js @@ -46,9 +46,16 @@ function _tail(options, files) { var shouldAppendNewline = false; files.forEach(function (file) { - if (!fs.existsSync(file) && file !== '-') { - common.error('no such file or directory: ' + file, { continue: true }); - return; + if (file !== '-') { + if (!fs.existsSync(file)) { + common.error('no such file or directory: ' + file, { continue: true }); + return; + } else if (fs.statSync(file).isDirectory()) { + common.error("error reading '" + file + "': Is a directory", { + continue: true, + }); + return; + } } var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); diff --git a/src/uniq.js b/src/uniq.js index 8f5da0028..30121616a 100644 --- a/src/uniq.js +++ b/src/uniq.js @@ -40,7 +40,18 @@ function _uniq(options, input, output) { // Check if this is coming from a pipe var pipe = common.readFromPipe(); - if (!input && !pipe) common.error('no input given'); + if (!pipe) { + if (!input) common.error('no input given'); + + if (!fs.existsSync(input)) { + common.error(input + ': No such file or directory'); + } else if (fs.statSync(input).isDirectory()) { + common.error("error reading '" + input + "'"); + } + } + if (output && fs.existsSync(output) && fs.statSync(output).isDirectory()) { + common.error(output + ': Is a directory'); + } var lines = (input ? fs.readFileSync(input, 'utf8') : pipe). trimRight(). diff --git a/test/cat.js b/test/cat.js index 654b304cd..53bd52257 100644 --- a/test/cat.js +++ b/test/cat.js @@ -25,6 +25,13 @@ test('nonexistent file', t => { t.is(result.stderr, 'cat: no such file or directory: /asdfasdf'); }); +test('directory', t => { + const result = shell.cat('resources/cat'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, 'cat: resources/cat: Is a directory'); +}); + // // Valids // diff --git a/test/head.js b/test/head.js index 19ee9e459..5d3beb3b2 100644 --- a/test/head.js +++ b/test/head.js @@ -18,9 +18,18 @@ test('no args', t => { test('file does not exist', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.head('/adsfasdf'); // file does not exist + const result = shell.head('/asdfasdf'); // file does not exist t.truthy(shell.error()); t.is(result.code, 1); + t.is(result.stderr, 'head: no such file or directory: /asdfasdf'); +}); + +test('directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.head('resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, "head: error reading 'resources/': Is a directory"); }); // diff --git a/test/sort.js b/test/sort.js index 23109d24e..ecba45447 100644 --- a/test/sort.js +++ b/test/sort.js @@ -25,11 +25,19 @@ test('no args', t => { test('file does not exist', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.sort('/adsfasdf'); + const result = shell.sort('/asdfasdf'); t.truthy(shell.error()); t.truthy(result.code); }); +test('directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.sort('resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, 'sort: read failed: resources/: Is a directory'); +}); + // // Valids // diff --git a/test/tail.js b/test/tail.js index 1ec7dd80f..8d3eba261 100644 --- a/test/tail.js +++ b/test/tail.js @@ -18,11 +18,19 @@ test('no args', t => { test('file does not exist', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.tail('/adsfasdf'); + const result = shell.tail('/asdfasdf'); t.truthy(shell.error()); t.is(result.code, 1); }); +test('directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.tail('resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, "tail: error reading 'resources/': Is a directory"); +}); + // // Valids // diff --git a/test/uniq.js b/test/uniq.js index ef4fad70f..751522561 100644 --- a/test/uniq.js +++ b/test/uniq.js @@ -18,11 +18,34 @@ test('no args', t => { test('file does not exist', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.sort('/adsfasdf'); + const result = shell.uniq('/asdfasdf'); t.truthy(shell.error()); t.truthy(result.code); }); +test('directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.uniq('resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, "uniq: error reading 'resources/'"); +}); + +test('output directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.uniq('resources/file1.txt', 'resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, 'uniq: 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/'); + t.is(result.code, 1); + t.truthy(shell.error()); +}); + // // Valids // From 15558cf67ad1d5da43e2bedcd2990c5878f09c35 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 16 May 2017 00:30:11 -0700 Subject: [PATCH 034/108] fix(mkdir): improve error handling around files (#721) * fix(mkdir): improve error handling around files In particular, this fixes: - if we try to overwrite a file with a mkdir - if we try to create a subdirectory of a file - adds `continue: true` in spots where we missed it Fixes #720 * Fixing tests on Windows --- src/mkdir.js | 10 ++++++++-- test/mkdir.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/mkdir.js b/src/mkdir.js index 115f75ca4..44b1b2162 100644 --- a/src/mkdir.js +++ b/src/mkdir.js @@ -57,9 +57,11 @@ function _mkdir(options, dirs) { dirs.forEach(function (dir) { try { - fs.lstatSync(dir); + var stat = fs.lstatSync(dir); if (!options.fullpath) { common.error('path already exists: ' + dir, { continue: true }); + } else if (stat.isFile()) { + common.error('cannot create directory ' + dir + ': File exists', { continue: true }); } return; // skip dir } catch (e) { @@ -80,12 +82,16 @@ function _mkdir(options, dirs) { fs.mkdirSync(dir, parseInt('0777', 8)); } } catch (e) { + var reason; if (e.code === 'EACCES') { - common.error('cannot create directory ' + dir + ': Permission denied'); + reason = 'Permission denied'; + } else if (e.code === 'ENOTDIR' || e.code === 'ENOENT') { + reason = 'Not a directory'; } else { /* istanbul ignore next */ throw e; } + common.error('cannot create directory ' + dir + ': ' + reason, { continue: true }); } }); return ''; diff --git a/test/mkdir.js b/test/mkdir.js index 9c0c57e0d..4093155d4 100644 --- a/test/mkdir.js +++ b/test/mkdir.js @@ -55,6 +55,34 @@ test('root path does not exist', t => { t.falsy(fs.existsSync('/asdfasdf/foobar')); }); +test('try to overwrite file', t => { + t.truthy(fs.statSync('resources/file1').isFile()); + const result = shell.mkdir('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()); +}); + +test('try to overwrite file, with -p', t => { + t.truthy(fs.statSync('resources/file1').isFile()); + const result = shell.mkdir('-p', '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()); +}); + +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(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')); +}); + test('Check for invalid permissions', t => { if (process.platform !== 'win32') { // This test case only works on unix, but should work on Windows as well From bbd8178cbaa56926759d1b7451a2171a21b24e3e Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Sat, 3 Jun 2017 22:26:10 -0700 Subject: [PATCH 035/108] Add node 8 to CI (#730) --- .travis.yml | 1 + appveyor.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index afd8f5603..02eb8bf81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ env: - NODE_VERSION="5" - NODE_VERSION="6" - NODE_VERSION="7" + - NODE_VERSION="8" # keep this blank to make sure there are no before_install steps before_install: diff --git a/appveyor.yml b/appveyor.yml index a081ad22e..ad698e448 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,6 @@ environment: matrix: + - nodejs_version: '8' - nodejs_version: '7' - nodejs_version: '6' - nodejs_version: '5' From a66e338b5fbcb4ede9d20ac7206d5d831c56af75 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 6 Jun 2017 20:58:14 -0700 Subject: [PATCH 036/108] docs(changelog): updated by Nate Fischer [ci skip] --- CHANGELOG.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6de319e18..5e0355bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # Change Log +## [Unreleased](https://github.com/shelljs/shelljs/tree/HEAD) + +[Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.7...HEAD) + +**Closed issues:** + +- Add node v8 to CI [\#729](https://github.com/shelljs/shelljs/issues/729) +- Exec not working in Electron ! [\#726](https://github.com/shelljs/shelljs/issues/726) +- is rechoir used anywhere? [\#723](https://github.com/shelljs/shelljs/issues/723) +- ShellJS: internal error on shelljs.mkdir\('myFile/myDir'\) [\#720](https://github.com/shelljs/shelljs/issues/720) +- Can't make sed perform global replace [\#719](https://github.com/shelljs/shelljs/issues/719) +- grep: option not recognized: l [\#717](https://github.com/shelljs/shelljs/issues/717) +- Problems getting code, stdout, stderr [\#715](https://github.com/shelljs/shelljs/issues/715) +- Copying hidden files fails on Windows 10 [\#711](https://github.com/shelljs/shelljs/issues/711) +- How am I suppose to handle errors with ShellJS? [\#707](https://github.com/shelljs/shelljs/issues/707) +- use cp\('-r', './src', './dist'\) bug [\#705](https://github.com/shelljs/shelljs/issues/705) +- Way to ignore files in globs. [\#699](https://github.com/shelljs/shelljs/issues/699) +- Buffer constructor is deprecated [\#694](https://github.com/shelljs/shelljs/issues/694) +- source command not working via exec method. [\#693](https://github.com/shelljs/shelljs/issues/693) +- Would you be interested in a PR for `open`? [\#692](https://github.com/shelljs/shelljs/issues/692) +- Get rid of common.platform in favor of process.platform [\#670](https://github.com/shelljs/shelljs/issues/670) +- Passing empty string to cp throws internal error [\#664](https://github.com/shelljs/shelljs/issues/664) +- Why does sed split files into an array, call replace on each line and rejoin? [\#645](https://github.com/shelljs/shelljs/issues/645) +- feat: cp & mv should not overwrite recently created files [\#631](https://github.com/shelljs/shelljs/issues/631) +- Echo tests unnecessarily run tests in own process [\#622](https://github.com/shelljs/shelljs/issues/622) +- rm -rf on a symbolic link to a dir deletes its contents [\#587](https://github.com/shelljs/shelljs/issues/587) +- "Cannot extract package" with node-webkit [\#181](https://github.com/shelljs/shelljs/issues/181) +- EBADF, bad file descriptor [\#180](https://github.com/shelljs/shelljs/issues/180) + +**Merged pull requests:** + +- 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)) +- fix\(grep, sed, sort, uniq\): Split only on newline characters [\#690](https://github.com/shelljs/shelljs/pull/690) ([freitagbr](https://github.com/freitagbr)) +- Refactor: Use process.platform across codebase [\#689](https://github.com/shelljs/shelljs/pull/689) ([freitagbr](https://github.com/freitagbr)) +- Remove contents of symlink to dir with rm -rf [\#688](https://github.com/shelljs/shelljs/pull/688) ([freitagbr](https://github.com/freitagbr)) +- Echo stdout [\#677](https://github.com/shelljs/shelljs/pull/677) ([nfischer](https://github.com/nfischer)) + ## [v0.7.7](https://github.com/shelljs/shelljs/tree/v0.7.7) (2017-03-09) [Full Changelog](https://github.com/shelljs/shelljs/compare/v0.7.6...v0.7.7) From 38645675f18b6369ffc161f2a6317e9ceab937c0 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 6 Jun 2017 21:01:21 -0700 Subject: [PATCH 037/108] 0.7.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb1c75428..c93e33420 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shelljs", - "version": "0.7.7", + "version": "0.7.8", "description": "Portable Unix shell commands for Node.js", "keywords": [ "shelljs", From 0ad6252f2e4d063cbd4a35b3d2ab299d4e91585f Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 6 Jun 2017 21:02:26 -0700 Subject: [PATCH 038/108] 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 039/108] 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 040/108] 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 041/108] 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 042/108] 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 043/108] 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 044/108] 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 045/108] 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 046/108] 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 047/108] 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 048/108] 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 049/108] 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 050/108] 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 051/108] 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 052/108] 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 053/108] 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 054/108] 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 055/108] 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 056/108] 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 057/108] 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 058/108] 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 059/108] 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 060/108] 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 061/108] 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 062/108] 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 063/108] 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 064/108] 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 065/108] 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 066/108] 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 067/108] 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 068/108] 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 069/108] 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 070/108] 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 071/108] 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 072/108] 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 073/108] 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 074/108] 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 075/108] 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 076/108] 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 077/108] 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 078/108] 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 079/108] 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 080/108] 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 081/108] 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 082/108] 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 083/108] 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 084/108] 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 085/108] 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 086/108] 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 087/108] 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 088/108] 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 089/108] 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 090/108] 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 091/108] 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 092/108] 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 093/108] 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 094/108] 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 095/108] 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 096/108] 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 097/108] 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 098/108] 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 099/108] 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 100/108] 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 101/108] 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 102/108] 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 103/108] 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 104/108] 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 105/108] 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 106/108] 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 107/108] 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 108/108] 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",