├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── bin └── jslint.js ├── doc └── jslint.md ├── jslint.conf.example ├── lib ├── collectorstream.js ├── color.js ├── fileopener.js ├── jslint-2012-02-03.js ├── jslint-2013-02-03.js ├── jslint-2013-08-13.js ├── jslint-2013-08-26.js ├── jslint-2013-09-22.js ├── jslint-2013-11-23.js ├── jslint-2014-01-26.js ├── jslint-2014-02-06.js ├── jslint-2014-04-21.js ├── jslint-2014-07-08.js ├── jslint-2015-05-08.js ├── jslint-2016-05-13.js ├── jslint-2016-07-13.js ├── jslint-2017-07-01.js ├── jslint-2018-01-26.js ├── jslint-2018-11-28.js ├── jslint-es5.js ├── jslint-es6.js ├── jslint-latest.js ├── jslint.js ├── jsonreportstream.js ├── linter.js ├── lintstream.js ├── main.js ├── nodelint.js ├── options.js ├── reporter.js ├── reportstream.js └── stream.js ├── package-lock.json ├── package.json └── test ├── color.js ├── fileopener.js ├── fixtures ├── bad.js └── good.js ├── linter.js ├── lintstream.js ├── main.js ├── nodelint.js ├── options.js ├── regression.js ├── reporter.js └── reportstream.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | 8 | [*.js, **/*.js] 9 | indent_size = 4 10 | indent_style = space 11 | 12 | [{package.json,.travis.yml}] 13 | indent_size = 2 14 | indent_style = space 15 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | *.js text eol=lf 4 | *.json test eol=lf 5 | 6 | # Custom for Visual Studio 7 | *.cs diff=csharp 8 | *.sln merge=union 9 | *.csproj merge=union 10 | *.vbproj merge=union 11 | *.fsproj merge=union 12 | *.dbproj merge=union 13 | 14 | # Standard to msysgit 15 | *.doc diff=astextplain 16 | *.DOC diff=astextplain 17 | *.docx diff=astextplain 18 | *.DOCX diff=astextplain 19 | *.dot diff=astextplain 20 | *.DOT diff=astextplain 21 | *.pdf diff=astextplain 22 | *.PDF diff=astextplain 23 | *.rtf diff=astextplain 24 | *.RTF diff=astextplain 25 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | jobs: 8 | main: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | node: [8, 10, 12] 13 | steps: 14 | - uses: actions/checkout@v1 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: ${{ matrix.node }} 18 | - name: Install and test 19 | run: | 20 | npm ci 21 | npm test 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | **.sw* 3 | .DS_Store* 4 | node_modules 5 | doc/jslint.html 6 | man/jslint.1 7 | coverage 8 | **/*~ 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.8" 4 | - "0.10" 5 | - "0.12" 6 | - "4" 7 | - "5" 8 | - "6" 9 | before_install: 10 | - "npm install -g npm@latest" 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | ## [0.12.1](https://github.com/reid/node-jslint/compare/v0.12.0...v0.12.1) (2019-01-28) 7 | 8 | ### Update to es6 latest (2018-11-28) 9 | Node doesn't like the 'export default' syntax, so I hacked it to use 'var'. 10 | 11 | ### Update dependencies 12 | * mocha => 5.2.0 13 | * glob => 7.1.3 14 | * nopt => 4.0.1 15 | * marked-man => 0.2.1 16 | 17 | 18 | ## [0.12.0](https://github.com/reid/node-jslint/compare/v0.10.3...v0.12.0) (2018-02-03) 19 | 20 | ### Update to es6 latest (2018-01-27) 21 | 22 | 23 | ## [0.10.3](https://github.com/reid/node-jslint/compare/v0.10.1...v0.10.3) (2016-08-03) 24 | 25 | 26 | ### Bug Fixes 27 | 28 | * **lib/jslint-es6:** update jslint-es6 to latest upstream, 2016-07-13 ([7ec74b6](https://github.com/reid/node-jslint/commit/7ec74b6)) 29 | * **package.json:** add license, update deps ([55baa7b](https://github.com/reid/node-jslint/commit/55baa7b)) 30 | 31 | 32 | 33 | 34 | ## [0.10.2](https://github.com/reid/node-jslint/compare/v0.10.0...v0.10.2) (2016-07-30) 35 | 36 | 37 | ### Bug Fixes 38 | 39 | * **package.json:** add license, update deps ([55baa7b](https://github.com/reid/node-jslint/commit/55baa7b)) 40 | 41 | ## Before 2016-07-30 42 | 43 | Version 0.9.0 contains the new BETA version of jslint for EcmaScript 6, 44 | which is a ground-up rewrite by Douglas Crockford. The `latest` alias 45 | still points to the last `es5` version of jslint; you can also use 46 | `--edition=es5` to get the (old) es5 version. To get the `es6` version 47 | you must use `--edition=es6`. 48 | 49 | 2015-07-29 Sam Mikes 50 | * lib/jslint-es6.js: latest jslint from upstream 51 | * lib/nodelint.js, test/regression.js: correctly report edition for post-es6 jslints, 52 | thanks to @bryanjhv for the bug report and fix 53 | 54 | 2015-02-19 Sam Mikes 55 | * lib/main.js, test/main.js: new option --no-filter to allow linting paths containing 'node_modules' 56 | 57 | 2014-12-16 Sam Mikes 58 | * lib/collector.js: new programmatic interface for collecting lint 59 | * lib/main.js, lib/nodelint.js: add callback to `runMain`, publicize 60 | 61 | 2014-10-22 Sam Mikes 62 | * test/regression.js: add file for misc github issues tests 63 | * package.json: avoid using prepublish 64 | 65 | 2014-09-10 Marshall Thompson 66 | * update jslint-latest to upstream edition 2014-07-08 67 | 68 | 2104-04-13 Sam Mikes 69 | 70 | * lib/linter.js: Fix issue #88 - support user-specified config file, support 71 | jslint.conf and .jslint.conf in addition to jslintrc, .jslintrc 72 | 73 | 2014-01-30 Sam Mikes 74 | 75 | * lib/linter.js: Fix Issue #80 - crash on empty jslintrc 76 | Underlying issue was test-then-read rather than just attempting to 77 | read and parse config, catching exceptions. 78 | 79 | 2014-01-27 Sam Mikes 80 | 81 | * Version 0.2.8 - update jslint-latest to upstream edition 2014-01-26 82 | 83 | 2013-12-18 Sam Mikes 84 | 85 | * Version 0.2.6 - move code from src/jslint.js to lib/main.js 86 | Update list of options in jslint.md 87 | Remove incorrect options from jslintrc.example (https://github.com/reid/node-jslint/issues/76) 88 | Document & enable use of --todo flag (https://github.com/reid/node-jslint/issues/76) 89 | 90 | Version 0.7.0 creates a new programmatic interface which is used by 91 | https://github.com/hapijs/lab 92 | 93 | Version 0.5.1 fixes a regression which crashes jslint when more than 94 | maxerr errors are in a single file. Thanks to Vasil Velichkov 95 | (@velichkov) for pointing this out. 96 | 97 | Version 0.5.0 reorganizes the loading interface, making it easier for 98 | other projects to use node-jslint to load a specific jslint edition. 99 | 100 | Version 0.4.0 exposes a stream interface to jslint. 101 | 102 | Version 0.3.4 supports globbing with * and ** expressions. 103 | 104 | Versions 0.2+ provide multiple editions of jslint to 105 | address backwards and forwards compatibility. 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2011 Yahoo! Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use of this software in source and binary forms, 5 | with or without modification, are permitted provided that the following 6 | conditions are met: 7 | 8 | * Redistributions of source code must retain the above 9 | copyright notice, this list of conditions and the 10 | following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the 14 | following disclaimer in the documentation and/or other 15 | materials provided with the distribution. 16 | 17 | * Neither the name of Yahoo! Inc. nor the names of its 18 | contributors may be used to endorse or promote products 19 | derived from this software without specific prior 20 | written permission of Yahoo! Inc. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 23 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | === 35 | 36 | This license applies to everything except JSLint. 37 | JSLint, located at lib/jslint.js, is copyright Douglas Crockford. 38 | JSLint is provided under a customized MIT license, which is 39 | included in the header of lib/jslint.js. 40 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN=bin/jslint.js 2 | SOURCES=$(shell find bin lib -name '*.js' ! -name 'jslint*.js' -print) 3 | 4 | install: 5 | npm i . 6 | 7 | # omit 'test' because running all tests is side-effect of asking for coverage 8 | prepublish: lint doc no-dos-endings check-coverage 9 | 10 | lint: $(SOURCES) 11 | node ./bin/jslint.js --edition=latest --this --terse $(SOURCES); echo 12 | 13 | test: 14 | ./node_modules/.bin/mocha -u tdd 15 | 16 | doc: man/jslint.1 doc/jslint.html 17 | 18 | man/jslint.1: doc/jslint.md 19 | mkdir -p man 20 | ./node_modules/.bin/marked-man $< > $@ 21 | 22 | doc/jslint.html: doc/jslint.md 23 | ./node_modules/.bin/marked-man --html $< > $@ 24 | 25 | no-dos-endings: 26 | file $(SOURCES) | grep -v CRLF >/dev/null 27 | 28 | cover: $(SOURCES) 29 | ./node_modules/.bin/istanbul cover -x "lib/jslint-*.js" --print=both ./node_modules/mocha/bin/_mocha -- -u tdd 30 | 31 | check-coverage: cover 32 | ./node_modules/.bin/istanbul check-coverage --statements 90 --branches 90 --functions 90 --lines 90 33 | 34 | .PHONY: install lint test doc no-dos-endings check-coverage 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## node-jslint 2 | 3 | Easily use [JSLint][] from the command line. 4 | 5 | jslint bin/jslint.js 6 | 7 | ## What's New 8 | 9 | Added latest jslint, 2018-01-27. 10 | 11 | Version 0.12.0 contains the latest jslint-es6 12 | 13 | See CHANGELOG.md for detailed change history 14 | 15 | ## Use the command-line client 16 | 17 | ### Install (both local and global are supported) 18 | 19 | npm i jslint 20 | 21 | ### Use the default jslint 22 | 23 | jslint lib/color.js 24 | 25 | ### Always use the latest jslint 26 | 27 | jslint --edition=latest lib/color.js 28 | 29 | ### Use a specific edition 30 | 31 | For example, edition 2013-02-03 which shipped with node-jslint 0.1.9: 32 | 33 | jslint --edition=2013-02-03 lib/color.js 34 | 35 | ## Use node-jslint programmatically 36 | 37 | ### Streams interface 38 | 39 | As of node-jslint 0.4.0, a streams interface is exposed. You can use it in client code like this: 40 | 41 | Install as a dependency: 42 | 43 | $ npm install --save jslint 44 | 45 | Pull it into your code with require: 46 | 47 | var LintStream = require('jslint').LintStream; 48 | 49 | Create and configure the stream linter: 50 | 51 | var options = { 52 | "edition": "latest", 53 | "length": 100 54 | }, 55 | l = new LintStream(options); 56 | 57 | Send files to the linter: 58 | 59 | var fileName, fileContents; 60 | l.write({file: fileName, body: fileContents}); 61 | 62 | Receive lint from the linter: 63 | 64 | l.on('data', function (chunk, encoding, callback) { 65 | // chunk is an object 66 | 67 | // chunk.file is whatever you supplied to write (see above) 68 | assert.deepEqual(chunk.file, fileName); 69 | 70 | // chunk.linted is an object holding the result from running JSLint 71 | // chunk.linted.ok is the boolean return code from JSLINT() 72 | // chunk.linted.errors is the array of errors, etc. 73 | // see JSLINT for the complete contents of the object 74 | 75 | callback(); 76 | }); 77 | 78 | You can only pass options to the LintStream when creating it. The `edition` option can be 79 | used to select different editions of JSLint. 80 | 81 | The LintStream is in object mode (objectMode: true). It expects an 82 | object with two properties: `file` and `body`. The `file` property 83 | can be used to pass metadata along with the file. The `body` property 84 | contains the file to be linted; it can be either a string or a Buffer. 85 | 86 | The LintStream emits `'data'` events containing an object with two properties. 87 | The `file` property is copied from the `file` property that is passed in. The 88 | `linted` property contains the results of running JSLINT. 89 | 90 | ### Simple interface 91 | 92 | The simple interface provides an edition-aware loader. This can be used as a frontend to 93 | node-jslint's collection of editions of the JSLINT code. 94 | 95 | var node_jslint = require('jslint'), 96 | JSLINT = node_jslint.load(edition); 97 | 98 | This exposes the same loading interface used in node-jslint, so it supports the special 99 | edition names `default` and `latest` as well as date-based edition names such as `2013-08-26` 100 | 101 | As of version 0.5.0, the `load` function also accepts filenames. To be recognized as a filename, 102 | the argument to load must contain a path-separator character (`/` or `\`) or end with the extension 103 | `.js`. 104 | 105 | 106 | ## Usage examples 107 | 108 | Multiple files 109 | 110 | jslint lib/color.js lib/reporter.js 111 | 112 | All JSLint options supported 113 | 114 | jslint --white --vars --regexp lib/color.js 115 | 116 | Defaults to true, but you can specify false 117 | 118 | jslint --bitwise false lib/color.js 119 | 120 | Pass arrays 121 | 122 | jslint --predef $ --predef Backbone lib/color.js 123 | 124 | JSLint your entire project 125 | 126 | jslint '**/*.js' 127 | 128 | ## Using JSLint with a config file 129 | 130 | Start with the included `jslint.conf.example` file, name it `jslint.conf` and customize your options 131 | per project or copy it to `$HOME/.jslint.conf` to apply your setting globally 132 | 133 | ## License 134 | 135 | See LICENSE file. 136 | 137 | [JSLint]: http://jslint.com/ 138 | -------------------------------------------------------------------------------- /bin/jslint.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var main = require("../lib/main.js"); 4 | 5 | main.runMain(main.parseArgs()); 6 | -------------------------------------------------------------------------------- /doc/jslint.md: -------------------------------------------------------------------------------- 1 | jslint(1) -- a code quality tool 2 | ================================ 3 | ## SYNOPSIS 4 | 5 | jslint.js [--anon] [--ass] [--bitwise] [--browser] [--closure] [--color] [--continue] [--debug] [--devel] [--edition] [--eqeq] [--es5] [--evil] [--forin] [--indent] [--json] [--maxerr] [--maxlen] [--newcap] [--node] [--nomen] [--on] [--passfail] [--plusplus] [--predef] [--properties] [--regexp] [--rhino] [--sloppy] [--stupid] [--sub] [--terse] [--todo] [--undef] [--unparam] [--vars] [--white] [--] ... 6 | 7 | ## DESCRIPTION 8 | 9 | JSLint is a static analysis tool to locate and correct style problems in Javascript (ECMAScript etc.) source code. 10 | 11 | ## META OPTIONS 12 | `--color` write output in color 13 | 14 | `--terse` report one error per line with parseable source file/line 15 | 16 | `--json` output in JSON format 17 | 18 | `--edition` specify which edition of jslint to use 19 | 20 | `--no-filter` allow linting files containing pattern `node_modules` 21 | 22 | ## LINTING OPTIONS 23 | `--ass` Tolerate assignment expressions 24 | 25 | `--bitwise` Tolerate bitwise operators 26 | 27 | `--browser` Assume a browser 28 | 29 | `--closure` Tolerate Google Closure idioms 30 | 31 | `--continue` Tolerate continue 32 | 33 | `--debug` Tolerate debugger statements 34 | 35 | `--devel` Assume console,alert, ... 36 | 37 | `--eqeq` Tolerate == and != 38 | 39 | `--evil` Tolerate eval 40 | 41 | `--forin` Tolerate unfiltered for in 42 | 43 | `--indent` Strict white space indentation 44 | 45 | `--maxerr` Maximum number of errors 46 | 47 | `--maxlen` Maximum line length 48 | 49 | `--newcap` Tolerate uncapitalized constructors 50 | 51 | `--node` Assume Node.js 52 | 53 | `--nomen` Tolerate dangling underscore in identifiers 54 | 55 | `--passfail` Stop on first error 56 | 57 | `--plusplus` Tolerate ++ and -- 58 | 59 | `--predef` Declare additional predefined globals 60 | 61 | `--properties` Require all property names to be declared with /*properties*/ 62 | 63 | `--regexp` Tolerate . and [^...]. in /RegExp/ 64 | 65 | `--rhino` Assume Rhino 66 | 67 | `--sloppy` Tolerate missing 'use strict' pragma 68 | 69 | `--stupid` Tolerate stupidity (typically, use of sync functions) 70 | 71 | `--sub` Tolerate inefficient subscripting 72 | 73 | `--todo` Tolerate TODO comments 74 | 75 | `--unparam` Tolerate unused parameters 76 | 77 | `--vars` Tolerate many var statements per function 78 | 79 | `--white` Tolerate messy white space 80 | 81 | ## DEPRECATED OPTIONS 82 | 83 | `--anon` Tolerate no space in anonymous function definition 84 | 85 | `--es5` Tolerate ECMAScript 5 syntax 86 | 87 | `--undef` Tolerate variables used before declaration 88 | 89 | `--on` Tolerate HTML event handlers 90 | 91 | `--windows` Assume existence of Windows globals 92 | 93 | ##EXAMPLES 94 | 95 | *Multiple files:* 96 | 97 | jslint lib/color.js lib/reporter.js 98 | 99 | *All JSLint options supported* 100 | 101 | jslint --white --vars --regexp lib/color.js 102 | 103 | *Defaults to true, but you can specify false* 104 | 105 | jslint --bitwise false lib/color.js 106 | 107 | *Pass arrays* 108 | 109 | jslint --predef $ --predef Backbone lib/color.js 110 | 111 | *JSLint your entire project* 112 | 113 | find . -name "*.js" -print0 | xargs -0 jslint 114 | 115 | *Using JSLint with a config file* 116 | 117 | Start with the included example jslintrc file and customize your options per project 118 | or copy it to $HOME/.jslintrc to apply your setting globally 119 | 120 | ##INSTALLATION 121 | 122 | To install jslint globally, use 123 | npm install jslint -g 124 | 125 | To install jslint locally, use 126 | npm install jslint 127 | 128 | When installed locally, jslint can be run as 129 | ./node_modules/.bin/jslint 130 | 131 | ##FILES 132 | 133 | jslint looks for the following config files at startup: 134 | 135 | $HOME/.jslintrc 136 | ./jslintrc 137 | ./.jslintrc 138 | 139 | The format of a jslint options file is a JSON file containing a single object 140 | where the keys are jslint option names and the values are the option argument; 141 | use `true` to enable and `false` to disable boolean options. An example of a 142 | valid option file is: 143 | 144 | { 145 | "vars": true, 146 | "white": true, 147 | "maxlen": 100, 148 | "predef": "foo,bar,baz" 149 | } 150 | 151 | Comments are not allowed in option files. 152 | 153 | ##PRECEDENCE 154 | 155 | The order of precedence for options is as follows: 156 | 157 | 1. in the $HOME/.jslintrc 158 | 1. in ./jslintrc or ./.jslintrc 159 | 1. on the command line 160 | 1. in a /\*jslint\*/ comment 161 | 162 | A higher number indicates a higher precedence, i.e. command line options 163 | override options specified by an options file, and /\*jslint\*/ comments 164 | in the file being examined have the highest precedence. 165 | 166 | ##EDITIONS 167 | 168 | You can now specify the edition of jslint with the *--edition* option. 169 | 170 | Future versions of this package may include newer editions of jslint; 171 | to always use the latest edition of jslint, specify --edition=latest: 172 | 173 | jslint --edition=latest lib/*.js 174 | 175 | The default edition of jslint will remain stable as long as the leading 176 | two components of the version number are the same. New minor editions 177 | may have a different default edition. 178 | 179 | The previous version of this package (0.1.9) shipped an older edition 180 | (2013-02-03) of jslint. To revert to that behavior but still have the 181 | new config file features, upgrade to 0.2.1 of this package and specify 182 | `edition: '2012-02-03'` in your jslintrc file or `--edition=2013-02-03` 183 | on the command line. 184 | 185 | We recommend the following practices: 186 | 187 | ###If your project is in maintenance mode 188 | 189 | Choose an edition of jslint and hardcode it into your project's lint config files, e.g., 190 | `edition: '2012-02-03'`. Specify a fixed version of jslint (e.g., "0.2.1") as a 191 | devDependency in package.json 192 | 193 | ###If your project needs temporary stability (e.g., release phase) 194 | 195 | Use the default edition of jslint (no `--edition` argument needed) and specify 196 | a fixed minor version (e.g, "~0.2") as a devDependency in package.json 197 | 198 | ###If you want the bleeding-edge version 199 | 200 | Specify `edition: 'latest'` and use any 'latest version' behavior in package.json, 201 | e.g., "*" or ">0.2.1" 202 | 203 | ##RETURN VALUES 204 | 205 | jslint returns 1 if it found any problems, 0 otherwise. 206 | 207 | ##AUTHOR 208 | 209 | jslint is written and maintained by Douglas Crockford [https://github.com/douglascrockford/JSLint](https://github.com/douglascrockford/JSLint) 210 | 211 | This package is node-jslint, which provides a command-line interface for 212 | running jslint using the nodejs platform. node-jslint was written by Reid Burke 213 | and is maintained by Reid Burke, Ryuichi Okumura, and Sam Mikes. 214 | 215 | ##BUGS 216 | 217 | There are no known bugs. Submit bugs to [https://github.com/reid/node-jslint/issues](https://github.com/reid/node-jslint/issues) 218 | 219 | Note that if you are reporting a problem with the way jslint works rather than the way 220 | the command-line tools work, we will probably refer you to the JSLint community [https://plus.google.com/communities/104441363299760713736](https://plus.google.com/communities/104441363299760713736) or the issue tracker at 221 | [https://github.com/douglascrockford/JSLint/issues](https://github.com/douglascrockford/JSLint/issues) 222 | -------------------------------------------------------------------------------- /jslint.conf.example: -------------------------------------------------------------------------------- 1 | { 2 | "evil":false, 3 | "indent":2, 4 | "vars":true, 5 | "passfail":false, 6 | "plusplus":false, 7 | "predef": "module,require" 8 | } 9 | -------------------------------------------------------------------------------- /lib/collectorstream.js: -------------------------------------------------------------------------------- 1 | // this file is lib/collectorstream.js 2 | // provides a stream interface to JSLint 3 | // 4 | // Copyright 2014 Cubane Canada Inc. 5 | // 6 | // Released under modified MIT/BSD 3-clause license 7 | // See LICENSE for details. 8 | 9 | 'use strict'; 10 | 11 | var util = require('util'), 12 | Transform = require('./stream').Transform, 13 | CollectorStream; 14 | 15 | CollectorStream = function CollectorStream_constructor(options) { 16 | if (!(this instanceof CollectorStream)) { 17 | return new CollectorStream(options); 18 | } 19 | 20 | Transform.call(this, {objectMode: true}); 21 | 22 | this.lint = []; 23 | 24 | this.allOK = true; 25 | }; 26 | util.inherits(CollectorStream, Transform); 27 | 28 | function CollectorStream_transform(chunk, ignore, callback) { 29 | // chunk: a package of lint data from JSLint 30 | this.lint.push([chunk.file, chunk.linted.errors]); 31 | 32 | this.allOK = this.allOK && chunk.linted.ok; 33 | 34 | callback(); 35 | } 36 | 37 | CollectorStream.prototype._transform = CollectorStream_transform; 38 | 39 | module.exports = CollectorStream; 40 | -------------------------------------------------------------------------------- /lib/color.js: -------------------------------------------------------------------------------- 1 | function color(code, string) { 2 | 'use strict'; 3 | return "\u001b[" + code + "m" + string + "\u001b[0m"; 4 | } 5 | 6 | function factory(code) { 7 | 'use strict'; 8 | return function (string) { 9 | return color(code, string); 10 | }; 11 | } 12 | 13 | module.exports = { 14 | bold: factory(1), 15 | red: factory(31), 16 | green: factory(32), 17 | yellow: factory(33), 18 | blue: factory(34), 19 | grey: factory(90) 20 | }; 21 | -------------------------------------------------------------------------------- /lib/fileopener.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'), 4 | Transform = require('./stream').Transform, 5 | fs = require('fs'); 6 | 7 | function FileOpener() { 8 | Transform.call(this, {objectMode: true}); 9 | } 10 | 11 | util.inherits(FileOpener, Transform); 12 | 13 | function FileOpener_transform(file, ignore, callback) { 14 | var stream = this; 15 | fs.readFile(file, 'utf8', function (err, data) { 16 | if (err) { 17 | stream.emit('error', err); 18 | return; 19 | } 20 | 21 | stream.push({file: file, body: data}); 22 | callback(); 23 | }); 24 | } 25 | 26 | FileOpener.prototype._transform = FileOpener_transform; 27 | 28 | module.exports = FileOpener; 29 | 30 | -------------------------------------------------------------------------------- /lib/jsonreportstream.js: -------------------------------------------------------------------------------- 1 | // this file is lib/reportstream.js 2 | // provides a stream interface to JSLint 3 | // 4 | // Copyright 2014 Cubane Canada Inc. 5 | // 6 | // Released under modified MIT/BSD 3-clause license 7 | // See LICENSE for details. 8 | 9 | (function () { 10 | 'use strict'; 11 | 12 | var util = require('util'), 13 | Transform = require('./stream').Transform, 14 | JSONReportStream; 15 | 16 | JSONReportStream = function JSONReportStream_constructor(options) { 17 | if (!(this instanceof JSONReportStream)) { 18 | return new JSONReportStream(options); 19 | } 20 | 21 | Transform.call(this, {objectMode: true}); 22 | 23 | this.allOK = true; 24 | }; 25 | util.inherits(JSONReportStream, Transform); 26 | 27 | function JSONReportStream_transform(chunk, ignore, callback) { 28 | // chunk: a package of lint data from JSLint 29 | this.emit('data', JSON.stringify([chunk.file, chunk.linted.errors])); 30 | 31 | this.allOK = this.allOK && chunk.linted.ok; 32 | 33 | callback(); 34 | } 35 | 36 | JSONReportStream.prototype._transform = JSONReportStream_transform; 37 | 38 | module.exports = JSONReportStream; 39 | 40 | }()); 41 | -------------------------------------------------------------------------------- /lib/linter.js: -------------------------------------------------------------------------------- 1 | function merge(source, add) { 2 | 'use strict'; 3 | 4 | var result = source || {}; 5 | 6 | if (!add) { 7 | return result; 8 | } 9 | 10 | Object.keys(add).forEach(function (prop) { 11 | if (!result.hasOwnProperty(prop)) { 12 | result[prop] = add[prop]; 13 | } 14 | }); 15 | 16 | return result; 17 | } 18 | exports.merge = merge; 19 | 20 | function preprocessScript(script) { 21 | 'use strict'; 22 | 23 | // Fix UTF8 with BOM 24 | if (script.charCodeAt(0) === 0xFEFF) { 25 | script = script.slice(1); 26 | } 27 | 28 | // remove shebang: replace it with empty line 29 | script = script.replace(/^#!.*/, ""); 30 | 31 | return script; 32 | } 33 | exports.preprocessScript = preprocessScript; 34 | 35 | exports.doLint = function (jslint, script, options) { 36 | 'use strict'; 37 | var ok, 38 | result; 39 | 40 | script = preprocessScript(script); 41 | 42 | ok = jslint(script, options); 43 | 44 | result = jslint.data(); 45 | if (result.ok === undefined) { 46 | result.ok = ok; 47 | } 48 | result.options = options; 49 | 50 | // es6 51 | result.errors = result.errors || result.warnings; 52 | 53 | return result; 54 | }; 55 | -------------------------------------------------------------------------------- /lib/lintstream.js: -------------------------------------------------------------------------------- 1 | // this file is lib/lintstream.js 2 | // provides a stream interface to JSLint 3 | // 4 | // Copyright 2014 Cubane Canada Inc. 5 | // 6 | // Released under modified MIT/BSD 3-clause license 7 | // See LICENSE for details. 8 | 9 | (function () { 10 | 'use strict'; 11 | 12 | var util = require('util'), 13 | Transform = require('./stream').Transform, 14 | nodelint = require('./nodelint'), 15 | optModule = require('./options'), 16 | linter = require('./linter'), 17 | LintStream; 18 | 19 | LintStream = function LintStream_constructor(options) { 20 | if (!(this instanceof LintStream)) { 21 | return new LintStream(options); 22 | } 23 | Transform.call(this, {objectMode: true}); 24 | 25 | // shallow copy options 26 | options = optModule.merge({}, options); 27 | this.JSlint = nodelint.load(options.edition); 28 | 29 | // initialize members 30 | this.options = options; 31 | this.linter = linter; 32 | }; 33 | util.inherits(LintStream, Transform); 34 | 35 | function LintStream_transform(chunk, ignore, callback) { 36 | var fileName = chunk.file, 37 | body = chunk.body, 38 | linted = this.linter.doLint(this.JSlint, body, this.options); 39 | 40 | this.push({file: fileName, linted: linted}); 41 | 42 | callback(); 43 | } 44 | 45 | LintStream.prototype._transform = LintStream_transform; 46 | 47 | module.exports = LintStream; 48 | 49 | }()); 50 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | var nodelint = require('./nodelint'); 2 | var optModule = require('./options'); 3 | var nopt = require("nopt"); 4 | var exit = require('exit'), 5 | glob = require('glob'); 6 | 7 | var LintStream = require('./lintstream.js'), 8 | ReportStream = require('./reportstream.js'), 9 | CollectorStream = require('./collectorstream.js'), 10 | JSONReportStream = require('./jsonreportstream.js'), 11 | FileOpener = require('./fileopener.js'); 12 | 13 | var con = console; 14 | var pro = process; 15 | 16 | exports.setConsole = function (c) { 17 | 'use strict'; 18 | con = c; 19 | }; 20 | 21 | exports.setProcess = function (p) { 22 | 'use strict'; 23 | pro = p; 24 | exit = pro.exit.bind(pro); 25 | }; 26 | 27 | function commandOptions() { 28 | 'use strict'; 29 | 30 | var commandOpts = { 31 | 'indent': Number, 32 | 'maxerr': Number, 33 | 'maxlen': Number, 34 | 'predef': [String, Array], 35 | 'edition': String, 36 | 'config': String 37 | }, 38 | /* flags defined in jslint-latest.js */ 39 | jslintFlags = [ 40 | 'ass', 'bitwise', 'browser', 'closure', 'continue', 41 | 'debug', 'devel', 'eqeq', 'evil', 'forin', 'newcap', 42 | 'node', 'nomen', 'passfail', 'plusplus', 'properties', 43 | 'regexp', 'rhino', 'unparam', 'sloppy', 'stupid', 'sub', 44 | 'todo', 'vars', 'white' 45 | ], 46 | /* flags used by node-jslint to control output */ 47 | cliFlags = [ 48 | 'json', 'color', 'terse', 'version', 'filter' 49 | ], 50 | /* not used by jslint-latest.js */ 51 | deprecatedFlags = [ 52 | 'anon', 'es5', 'on', 'undef', 'windows' 53 | ], 54 | allFlags = jslintFlags.concat(cliFlags).concat(deprecatedFlags); 55 | 56 | allFlags.forEach(function (option) { 57 | commandOpts[option] = Boolean; 58 | }); 59 | 60 | return commandOpts; 61 | } 62 | exports.commandOptions = commandOptions; 63 | 64 | function die(why) { 65 | 'use strict'; 66 | var o = commandOptions(); 67 | con.warn(why); 68 | con.warn("Usage: " + pro.argv[1] + 69 | " [--" + Object.keys(o).sort().join("] [--") + 70 | "] [--] ..."); 71 | exit(1); 72 | } 73 | 74 | function parseArgs(argv) { 75 | 'use strict'; 76 | var args = nopt(commandOptions(), {}, argv); 77 | 78 | if (args.filter === undefined) { 79 | args.filter = true; 80 | } 81 | 82 | return args; 83 | } 84 | exports.parseArgs = parseArgs; 85 | 86 | exports.reportVersion = function reportVersion(callback, options) { 87 | 'use strict'; 88 | process.nextTick(function () { 89 | var package_data = require('../package.json'), 90 | version = package_data.version, 91 | edition = nodelint.load(options.edition).edition; 92 | 93 | callback("node-jslint version: " + version + " JSLint edition " + edition); 94 | }); 95 | 96 | }; 97 | 98 | function expandGlob(glob) { 99 | 'use strict'; 100 | 101 | return function (pattern) { 102 | return glob.sync(pattern); 103 | }; 104 | } 105 | exports.expandGlob = expandGlob; 106 | 107 | function noNodeModules(file) { 108 | 'use strict'; 109 | return file.indexOf('node_modules') === -1; 110 | } 111 | exports.noNodeModules = noNodeModules; 112 | 113 | function flatten(a, b) { 114 | 'use strict'; 115 | 116 | return a.concat(b); 117 | } 118 | 119 | function globFiles(list, glob, filter) { 120 | 'use strict'; 121 | var remain = []; 122 | 123 | remain = list.map(expandGlob(glob)) 124 | .reduce(flatten, []); 125 | 126 | if (filter) { 127 | remain = remain.filter(noNodeModules); 128 | } 129 | 130 | return remain; 131 | } 132 | exports.globFiles = globFiles; 133 | 134 | function makeReporter(parsed) { 135 | 'use strict'; 136 | var reporter; 137 | 138 | if (parsed.json) { 139 | reporter = new JSONReportStream(parsed); 140 | } else if (parsed.collector) { 141 | reporter = new CollectorStream(parsed); 142 | } else { 143 | reporter = new ReportStream(parsed); 144 | } 145 | 146 | reporter.on('data', function (chunk) { 147 | if (chunk === '.') { 148 | pro.stderr.write(chunk); 149 | } else { 150 | con.log(chunk); 151 | } 152 | }); 153 | 154 | return reporter; 155 | } 156 | exports.makeReporter = makeReporter; 157 | 158 | exports.runMain = function (options, cb) { 159 | 'use strict'; 160 | 161 | if (options.version) { 162 | exports.reportVersion(con.log, options); 163 | return; 164 | } 165 | 166 | if (!options.argv.remain.length) { 167 | die("No files specified."); 168 | } 169 | 170 | var procOptions = optModule.getOptions(process.env.HOME, options), 171 | files = globFiles(options.argv.remain, glob, options.filter), 172 | opener = new FileOpener(), 173 | linter = new LintStream(procOptions), 174 | reporter = makeReporter(procOptions); 175 | 176 | opener.pipe(linter); 177 | linter.pipe(reporter); 178 | 179 | reporter.on('finish', function () { 180 | if (cb) { 181 | return cb(null, reporter.lint); 182 | } 183 | 184 | if (reporter.allOK) { 185 | return exit(0); 186 | } 187 | exit(1); 188 | }); 189 | 190 | files.forEach(function (file) { 191 | opener.write(file); 192 | }); 193 | opener.end(); 194 | }; 195 | -------------------------------------------------------------------------------- /lib/nodelint.js: -------------------------------------------------------------------------------- 1 | var con = console, 2 | vm = require("vm"), 3 | fs = require("fs"), 4 | path = require('path'), 5 | linter = require('./linter.js'), 6 | main = require('./main.js'), 7 | LintStream = require('./lintstream.js'); 8 | 9 | exports.LintStream = LintStream; 10 | 11 | exports.linter = linter; 12 | 13 | exports.runMain = main.runMain; 14 | 15 | exports.setConsole = function (c) { 16 | 'use strict'; 17 | con = c; 18 | }; 19 | 20 | function looksLikeFileName(edition) { 21 | 'use strict'; 22 | 23 | // contains .js or a path separator character '/' or '\' 24 | return (/\.js|\/|\\/).test(edition); 25 | } 26 | exports.looksLikeFileName = looksLikeFileName; 27 | 28 | exports.load = function (edition) { 29 | 'use strict'; 30 | 31 | var ctx = vm.createContext(), 32 | fileName, 33 | jslintSource; 34 | 35 | function makePathFromName(name) { 36 | return path.join(__dirname, name) + ".js"; 37 | } 38 | 39 | function makePathFromEdition(edition) { 40 | return makePathFromName("jslint-" + edition); 41 | } 42 | 43 | function read(name) { 44 | return fs.readFileSync(name); 45 | } 46 | 47 | 48 | if (edition) { 49 | if (looksLikeFileName(edition)) { 50 | fileName = edition; 51 | } else { 52 | fileName = makePathFromEdition(edition); 53 | } 54 | 55 | try { 56 | jslintSource = read(fileName); 57 | } catch (err) { 58 | con.warn("Unable to load edition " + edition + ", reverting to default. " + err); 59 | } 60 | } 61 | 62 | if (!jslintSource) { 63 | jslintSource = read(makePathFromName("jslint")); 64 | } 65 | 66 | vm.runInContext(jslintSource, ctx); 67 | 68 | if (!ctx.JSLINT) { 69 | ctx.JSLINT = function JSLINT(script, options) { 70 | var data = ctx.jslint(script, options, options.predef); 71 | ctx.JSLINT.data = function () { 72 | return data; 73 | }; 74 | }; 75 | ctx.JSLINT.edition = ctx.jslint('').edition; 76 | } 77 | 78 | return ctx.JSLINT; 79 | 80 | }; 81 | -------------------------------------------------------------------------------- /lib/options.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var path = require('path'), 5 | fs = require('fs'), 6 | con = console; 7 | 8 | exports.setConsole = function (c) { 9 | con = c; 10 | }; 11 | 12 | function merge(source, add) { 13 | var result = source || {}; 14 | 15 | if (!add) { 16 | return result; 17 | } 18 | 19 | Object.keys(add).forEach(function (prop) { 20 | if (!result.hasOwnProperty(prop)) { 21 | result[prop] = add[prop]; 22 | } 23 | }); 24 | 25 | return result; 26 | } 27 | exports.merge = merge; 28 | 29 | function loadAndParseConfig(filePath) { 30 | try { 31 | return JSON.parse(fs.readFileSync(filePath, "utf-8")); 32 | } catch (err) { 33 | if (filePath && err.code !== "ENOENT") { 34 | con.warn('Error reading config file "' + filePath + '": ' + err); 35 | } 36 | } 37 | } 38 | exports.loadAndParseConfig = loadAndParseConfig; 39 | 40 | function addDefaults(options) { 41 | 42 | options = merge(options, {node: true, es5: true}); 43 | 44 | return options; 45 | } 46 | 47 | function notFalsy(n) { 48 | return n; 49 | } 50 | 51 | function splitPredefs(options) { 52 | if (!options.predef) { 53 | return options; 54 | } 55 | if (Array.isArray(options.predef)) { 56 | return options; 57 | } 58 | 59 | options.predef = options.predef.split(',').filter(notFalsy); 60 | 61 | return options; 62 | } 63 | 64 | function preprocessOptions(options, config) { 65 | options = merge({}, options); 66 | 67 | options = merge(options, config); 68 | 69 | options = addDefaults(options); 70 | 71 | options = splitPredefs(options); 72 | 73 | return options; 74 | } 75 | 76 | function mergeConfigs(home, project) { 77 | var homeConfig, 78 | cwdConfig, 79 | config; 80 | 81 | home.some(function (file) { 82 | homeConfig = loadAndParseConfig(file); 83 | return homeConfig; 84 | }); 85 | 86 | project.some(function (file) { 87 | cwdConfig = loadAndParseConfig(file); 88 | return cwdConfig; 89 | }); 90 | 91 | config = merge(cwdConfig, homeConfig); 92 | 93 | return config; 94 | } 95 | exports.mergeConfigs = mergeConfigs; 96 | 97 | function loadConfig(h, configFile) { 98 | var home = h || '', 99 | homeConfigs = ['.jslint.conf', '.jslintrc'], 100 | projectConfigs = ['jslint.conf', '.jslint.conf', 'jslintrc', '.jslintrc']; 101 | 102 | if (configFile) { 103 | // explicitly specified config file overrides default config file name, path 104 | homeConfigs = [configFile]; 105 | } else { 106 | homeConfigs = homeConfigs.map(function (file) { 107 | return path.join(home, file); 108 | }); 109 | } 110 | 111 | projectConfigs = projectConfigs.map(function (file) { 112 | return path.join(process.cwd(), file); 113 | }); 114 | 115 | return mergeConfigs(homeConfigs, projectConfigs); 116 | } 117 | exports.loadConfig = loadConfig; 118 | 119 | function options_getOptions(homedir, options) { 120 | var config = loadConfig(homedir, options.config); 121 | 122 | return preprocessOptions(options, config); 123 | } 124 | 125 | exports.preprocessOptions = preprocessOptions; 126 | exports.getOptions = options_getOptions; 127 | exports.splitPredefs = splitPredefs; 128 | exports.addDefaults = addDefaults; 129 | 130 | }()); 131 | -------------------------------------------------------------------------------- /lib/reporter.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var color = require("./color"); 5 | 6 | exports.logger = { 7 | log: (console.log).bind(console), 8 | err: (process.stderr.write).bind(process.stderr) 9 | }; 10 | 11 | exports.setLogger = function (l) { 12 | this.logger = l; 13 | }; 14 | 15 | exports.makeReporter = function (logger, colorize, terse) { 16 | return { 17 | logger: logger, 18 | colorize: colorize, 19 | terse: terse, 20 | report: function (file, lint) { 21 | return exports.report.call(this, file, lint, this.colorize, this.terse); 22 | } 23 | }; 24 | }; 25 | 26 | exports.report = function (file, lint, colorize, terse) { 27 | var line, 28 | pad, 29 | errors, 30 | fudge = Number(lint.option && lint.option.fudge) || 0, 31 | logger = this.logger, 32 | fileMessage; 33 | 34 | function c(format, str) { 35 | if (colorize) { 36 | return color[format](str); 37 | } 38 | return str; 39 | } 40 | 41 | fileMessage = "\n" + c('bold', file); 42 | 43 | function row(e) { 44 | return e.line + fudge; 45 | } 46 | function col(e) { 47 | return (e.character || e.column) + fudge; 48 | } 49 | function evidence(e) { 50 | return e.evidence || (lint.lines && lint.lines[e.line]) || ''; 51 | } 52 | function message(e) { 53 | return e.reason || e.message; 54 | } 55 | 56 | if (!lint.ok) { 57 | // remove nulls 58 | errors = lint.errors;// || lint.warnings; 59 | errors = errors.filter(function (e) { 60 | return e; 61 | }); 62 | 63 | if (terse) { 64 | errors.forEach(function (e) { 65 | logger.log(file + ':' + row(e) + ':' + col(e) + ': ' + message(e)); 66 | }); 67 | } else { 68 | logger.log(fileMessage); 69 | errors.forEach(function (e, i) { 70 | pad = "#" + String(i + 1); 71 | while (pad.length < 3) { 72 | pad = ' ' + pad; 73 | } 74 | line = ' // Line ' + row(e) + ', Pos ' + col(e); 75 | 76 | logger.log(pad + ' ' + c('yellow', message(e))); 77 | logger.log(' ' + evidence(e).trim() + c('grey', line)); 78 | }); 79 | } 80 | } else { 81 | if (terse) { 82 | logger.err("."); 83 | } else { 84 | logger.log(fileMessage + " is " + c('green', 'OK') + "."); 85 | } 86 | } 87 | 88 | return lint.ok; 89 | }; 90 | 91 | }()); 92 | -------------------------------------------------------------------------------- /lib/reportstream.js: -------------------------------------------------------------------------------- 1 | // this file is lib/reportstream.js 2 | // provides a stream interface to JSLint 3 | // 4 | // Copyright 2014 Cubane Canada Inc. 5 | // 6 | // Released under modified MIT/BSD 3-clause license 7 | // See LICENSE for details. 8 | 9 | (function () { 10 | 'use strict'; 11 | 12 | var util = require('util'), 13 | Transform = require('./stream').Transform, 14 | reporter = require('./reporter'), 15 | ReportStream; 16 | 17 | 18 | ReportStream = function ReportStream_constructor(options) { 19 | var stream = this; 20 | 21 | if (!(this instanceof ReportStream)) { 22 | return new ReportStream(options); 23 | } 24 | 25 | options = options || {}; 26 | options.objectMode = true; 27 | Transform.call(this, options); 28 | 29 | this.reporter = reporter.makeReporter( 30 | { 31 | log: function (s) { 32 | stream.emit('data', s); 33 | }, 34 | err: function (s) { 35 | stream.emit('data', s); 36 | } 37 | }, 38 | options.color, 39 | options.terse 40 | ); 41 | 42 | this.allOK = true; 43 | 44 | }; 45 | util.inherits(ReportStream, Transform); 46 | 47 | function ReportStream_transform(chunk, ignore, callback) { 48 | // chunk: a package of lint data from JSLint 49 | 50 | this.reporter.report(chunk.file, chunk.linted); 51 | 52 | this.allOK = this.allOK && chunk.linted.ok; 53 | 54 | callback(); 55 | } 56 | 57 | ReportStream.prototype._transform = ReportStream_transform; 58 | 59 | module.exports = ReportStream; 60 | 61 | }()); 62 | -------------------------------------------------------------------------------- /lib/stream.js: -------------------------------------------------------------------------------- 1 | module.exports = require('readable-stream'); 2 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jslint", 3 | "version": "0.12.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "abbrev": { 8 | "version": "1.0.7", 9 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz", 10 | "integrity": "sha1-W2A1su6dT7XPhZ8Iqb6BsghJGEM=" 11 | }, 12 | "amdefine": { 13 | "version": "1.0.1", 14 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 15 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", 16 | "dev": true, 17 | "optional": true 18 | }, 19 | "argparse": { 20 | "version": "1.0.9", 21 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", 22 | "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", 23 | "dev": true, 24 | "requires": { 25 | "sprintf-js": "~1.0.2" 26 | } 27 | }, 28 | "async": { 29 | "version": "1.5.2", 30 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 31 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 32 | "dev": true 33 | }, 34 | "balanced-match": { 35 | "version": "1.0.0", 36 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 37 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 38 | }, 39 | "brace-expansion": { 40 | "version": "1.1.8", 41 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 42 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 43 | "requires": { 44 | "balanced-match": "^1.0.0", 45 | "concat-map": "0.0.1" 46 | } 47 | }, 48 | "browser-stdout": { 49 | "version": "1.3.1", 50 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 51 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 52 | "dev": true 53 | }, 54 | "buffer-shims": { 55 | "version": "1.0.0", 56 | "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", 57 | "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=" 58 | }, 59 | "commander": { 60 | "version": "2.15.1", 61 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 62 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", 63 | "dev": true 64 | }, 65 | "concat-map": { 66 | "version": "0.0.1", 67 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 68 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 69 | }, 70 | "core-util-is": { 71 | "version": "1.0.2", 72 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 73 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 74 | }, 75 | "debug": { 76 | "version": "3.1.0", 77 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 78 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 79 | "dev": true, 80 | "requires": { 81 | "ms": "2.0.0" 82 | } 83 | }, 84 | "deep-is": { 85 | "version": "0.1.3", 86 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 87 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 88 | "dev": true 89 | }, 90 | "diff": { 91 | "version": "3.5.0", 92 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 93 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 94 | "dev": true 95 | }, 96 | "escape-string-regexp": { 97 | "version": "1.0.5", 98 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 99 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 100 | "dev": true 101 | }, 102 | "escodegen": { 103 | "version": "1.8.0", 104 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.0.tgz", 105 | "integrity": "sha1-skaq6CnOc9WeLFVyc1nt0cEwqBs=", 106 | "dev": true, 107 | "requires": { 108 | "esprima": "^2.7.1", 109 | "estraverse": "^1.9.1", 110 | "esutils": "^2.0.2", 111 | "optionator": "^0.8.1", 112 | "source-map": "~0.2.0" 113 | } 114 | }, 115 | "esprima": { 116 | "version": "2.7.3", 117 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", 118 | "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", 119 | "dev": true 120 | }, 121 | "estraverse": { 122 | "version": "1.9.3", 123 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", 124 | "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", 125 | "dev": true 126 | }, 127 | "esutils": { 128 | "version": "2.0.2", 129 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 130 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 131 | "dev": true 132 | }, 133 | "exit": { 134 | "version": "0.1.2", 135 | "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", 136 | "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" 137 | }, 138 | "fast-levenshtein": { 139 | "version": "2.0.6", 140 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 141 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 142 | "dev": true 143 | }, 144 | "fs.extra": { 145 | "version": "1.3.2", 146 | "resolved": "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz", 147 | "integrity": "sha1-3QI/kwE77iRTHxszUUw3sg/ZM0k=", 148 | "dev": true, 149 | "requires": { 150 | "fs-extra": "~0.6.1", 151 | "mkdirp": "~0.3.5", 152 | "walk": "^2.3.9" 153 | }, 154 | "dependencies": { 155 | "fs-extra": { 156 | "version": "0.6.4", 157 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz", 158 | "integrity": "sha1-9G8MdbeEH40gCzNIzU1pHVoJnRU=", 159 | "dev": true, 160 | "requires": { 161 | "jsonfile": "~1.0.1", 162 | "mkdirp": "0.3.x", 163 | "ncp": "~0.4.2", 164 | "rimraf": "~2.2.0" 165 | }, 166 | "dependencies": { 167 | "jsonfile": { 168 | "version": "1.0.1", 169 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz", 170 | "integrity": "sha1-6l7+QLg2kLmGZ2FKc5L8YOhCwN0=", 171 | "dev": true 172 | }, 173 | "ncp": { 174 | "version": "0.4.2", 175 | "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", 176 | "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", 177 | "dev": true 178 | }, 179 | "rimraf": { 180 | "version": "2.2.8", 181 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", 182 | "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", 183 | "dev": true 184 | } 185 | } 186 | }, 187 | "mkdirp": { 188 | "version": "0.3.5", 189 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", 190 | "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", 191 | "dev": true 192 | }, 193 | "walk": { 194 | "version": "2.3.9", 195 | "resolved": "https://registry.npmjs.org/walk/-/walk-2.3.9.tgz", 196 | "integrity": "sha1-MbTbZnjyrgHDnqn7hyWpAx5Vins=", 197 | "dev": true, 198 | "requires": { 199 | "foreachasync": "^3.0.0" 200 | }, 201 | "dependencies": { 202 | "foreachasync": { 203 | "version": "3.0.0", 204 | "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", 205 | "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=", 206 | "dev": true 207 | } 208 | } 209 | } 210 | } 211 | }, 212 | "fs.realpath": { 213 | "version": "1.0.0", 214 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 215 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 216 | }, 217 | "glob": { 218 | "version": "7.1.3", 219 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 220 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 221 | "requires": { 222 | "fs.realpath": "^1.0.0", 223 | "inflight": "^1.0.4", 224 | "inherits": "2", 225 | "minimatch": "^3.0.4", 226 | "once": "^1.3.0", 227 | "path-is-absolute": "^1.0.0" 228 | } 229 | }, 230 | "growl": { 231 | "version": "1.10.5", 232 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 233 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 234 | "dev": true 235 | }, 236 | "handlebars": { 237 | "version": "4.7.6", 238 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", 239 | "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", 240 | "dev": true, 241 | "requires": { 242 | "minimist": "^1.2.5", 243 | "neo-async": "^2.6.0", 244 | "source-map": "^0.6.1", 245 | "uglify-js": "^3.1.4", 246 | "wordwrap": "^1.0.0" 247 | }, 248 | "dependencies": { 249 | "minimist": { 250 | "version": "1.2.5", 251 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 252 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 253 | "dev": true 254 | }, 255 | "source-map": { 256 | "version": "0.6.1", 257 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 258 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 259 | "dev": true 260 | } 261 | } 262 | }, 263 | "has-flag": { 264 | "version": "1.0.0", 265 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 266 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 267 | "dev": true 268 | }, 269 | "he": { 270 | "version": "1.1.1", 271 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 272 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 273 | "dev": true 274 | }, 275 | "inflight": { 276 | "version": "1.0.6", 277 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 278 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 279 | "requires": { 280 | "once": "^1.3.0", 281 | "wrappy": "1" 282 | } 283 | }, 284 | "inherits": { 285 | "version": "2.0.3", 286 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 287 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 288 | }, 289 | "isarray": { 290 | "version": "1.0.0", 291 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 292 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 293 | }, 294 | "isexe": { 295 | "version": "2.0.0", 296 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 297 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 298 | "dev": true 299 | }, 300 | "istanbul": { 301 | "version": "0.4.5", 302 | "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", 303 | "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", 304 | "dev": true, 305 | "requires": { 306 | "abbrev": "1.0.x", 307 | "async": "1.x", 308 | "escodegen": "1.8.x", 309 | "esprima": "2.7.x", 310 | "glob": "^5.0.15", 311 | "handlebars": "^4.0.1", 312 | "js-yaml": "3.x", 313 | "mkdirp": "0.5.x", 314 | "nopt": "3.x", 315 | "once": "1.x", 316 | "resolve": "1.1.x", 317 | "supports-color": "^3.1.0", 318 | "which": "^1.1.1", 319 | "wordwrap": "^1.0.0" 320 | }, 321 | "dependencies": { 322 | "glob": { 323 | "version": "5.0.15", 324 | "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", 325 | "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", 326 | "dev": true, 327 | "requires": { 328 | "inflight": "^1.0.4", 329 | "inherits": "2", 330 | "minimatch": "2 || 3", 331 | "once": "^1.3.0", 332 | "path-is-absolute": "^1.0.0" 333 | } 334 | }, 335 | "nopt": { 336 | "version": "3.0.6", 337 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", 338 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", 339 | "dev": true, 340 | "requires": { 341 | "abbrev": "1" 342 | } 343 | } 344 | } 345 | }, 346 | "js-yaml": { 347 | "version": "3.13.1", 348 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 349 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 350 | "dev": true, 351 | "requires": { 352 | "argparse": "^1.0.7", 353 | "esprima": "^4.0.0" 354 | }, 355 | "dependencies": { 356 | "esprima": { 357 | "version": "4.0.1", 358 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 359 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 360 | "dev": true 361 | } 362 | } 363 | }, 364 | "levn": { 365 | "version": "0.3.0", 366 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 367 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 368 | "dev": true, 369 | "requires": { 370 | "prelude-ls": "~1.1.2", 371 | "type-check": "~0.3.2" 372 | } 373 | }, 374 | "marked": { 375 | "version": "0.3.19", 376 | "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", 377 | "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", 378 | "dev": true 379 | }, 380 | "marked-man": { 381 | "version": "0.2.1", 382 | "resolved": "https://registry.npmjs.org/marked-man/-/marked-man-0.2.1.tgz", 383 | "integrity": "sha1-8lknFIHeO1ByY0ifUiG3xaz9I4M=", 384 | "dev": true, 385 | "requires": { 386 | "marked": "^0.3.2" 387 | } 388 | }, 389 | "minimatch": { 390 | "version": "3.0.4", 391 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 392 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 393 | "requires": { 394 | "brace-expansion": "^1.1.7" 395 | } 396 | }, 397 | "mkdirp": { 398 | "version": "0.5.1", 399 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 400 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 401 | "dev": true, 402 | "requires": { 403 | "minimist": "0.0.8" 404 | }, 405 | "dependencies": { 406 | "minimist": { 407 | "version": "0.0.8", 408 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 409 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 410 | "dev": true 411 | } 412 | } 413 | }, 414 | "mocha": { 415 | "version": "5.2.0", 416 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", 417 | "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", 418 | "dev": true, 419 | "requires": { 420 | "browser-stdout": "1.3.1", 421 | "commander": "2.15.1", 422 | "debug": "3.1.0", 423 | "diff": "3.5.0", 424 | "escape-string-regexp": "1.0.5", 425 | "glob": "7.1.2", 426 | "growl": "1.10.5", 427 | "he": "1.1.1", 428 | "minimatch": "3.0.4", 429 | "mkdirp": "0.5.1", 430 | "supports-color": "5.4.0" 431 | }, 432 | "dependencies": { 433 | "glob": { 434 | "version": "7.1.2", 435 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 436 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 437 | "dev": true, 438 | "requires": { 439 | "fs.realpath": "^1.0.0", 440 | "inflight": "^1.0.4", 441 | "inherits": "2", 442 | "minimatch": "^3.0.4", 443 | "once": "^1.3.0", 444 | "path-is-absolute": "^1.0.0" 445 | } 446 | }, 447 | "has-flag": { 448 | "version": "3.0.0", 449 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 450 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 451 | "dev": true 452 | }, 453 | "supports-color": { 454 | "version": "5.4.0", 455 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 456 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 457 | "dev": true, 458 | "requires": { 459 | "has-flag": "^3.0.0" 460 | } 461 | } 462 | } 463 | }, 464 | "ms": { 465 | "version": "2.0.0", 466 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 467 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 468 | "dev": true 469 | }, 470 | "neo-async": { 471 | "version": "2.6.1", 472 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", 473 | "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", 474 | "dev": true 475 | }, 476 | "nopt": { 477 | "version": "4.0.1", 478 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", 479 | "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", 480 | "requires": { 481 | "abbrev": "1", 482 | "osenv": "^0.1.4" 483 | } 484 | }, 485 | "once": { 486 | "version": "1.4.0", 487 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 488 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 489 | "requires": { 490 | "wrappy": "1" 491 | } 492 | }, 493 | "optionator": { 494 | "version": "0.8.2", 495 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 496 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 497 | "dev": true, 498 | "requires": { 499 | "deep-is": "~0.1.3", 500 | "fast-levenshtein": "~2.0.4", 501 | "levn": "~0.3.0", 502 | "prelude-ls": "~1.1.2", 503 | "type-check": "~0.3.2", 504 | "wordwrap": "~1.0.0" 505 | } 506 | }, 507 | "os-homedir": { 508 | "version": "1.0.2", 509 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 510 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" 511 | }, 512 | "os-tmpdir": { 513 | "version": "1.0.2", 514 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 515 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" 516 | }, 517 | "osenv": { 518 | "version": "0.1.5", 519 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", 520 | "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", 521 | "requires": { 522 | "os-homedir": "^1.0.0", 523 | "os-tmpdir": "^1.0.0" 524 | } 525 | }, 526 | "path-is-absolute": { 527 | "version": "1.0.1", 528 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 529 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 530 | }, 531 | "prelude-ls": { 532 | "version": "1.1.2", 533 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 534 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 535 | "dev": true 536 | }, 537 | "process-nextick-args": { 538 | "version": "1.0.7", 539 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 540 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" 541 | }, 542 | "readable-stream": { 543 | "version": "2.1.5", 544 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", 545 | "integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=", 546 | "requires": { 547 | "buffer-shims": "^1.0.0", 548 | "core-util-is": "~1.0.0", 549 | "inherits": "~2.0.1", 550 | "isarray": "~1.0.0", 551 | "process-nextick-args": "~1.0.6", 552 | "string_decoder": "~0.10.x", 553 | "util-deprecate": "~1.0.1" 554 | } 555 | }, 556 | "resolve": { 557 | "version": "1.1.7", 558 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", 559 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", 560 | "dev": true 561 | }, 562 | "source-map": { 563 | "version": "0.2.0", 564 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", 565 | "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", 566 | "dev": true, 567 | "optional": true, 568 | "requires": { 569 | "amdefine": ">=0.0.4" 570 | } 571 | }, 572 | "sprintf-js": { 573 | "version": "1.0.3", 574 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 575 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 576 | "dev": true 577 | }, 578 | "string_decoder": { 579 | "version": "0.10.31", 580 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 581 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 582 | }, 583 | "supports-color": { 584 | "version": "3.2.3", 585 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", 586 | "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", 587 | "dev": true, 588 | "requires": { 589 | "has-flag": "^1.0.0" 590 | } 591 | }, 592 | "type-check": { 593 | "version": "0.3.2", 594 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 595 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 596 | "dev": true, 597 | "requires": { 598 | "prelude-ls": "~1.1.2" 599 | } 600 | }, 601 | "uglify-js": { 602 | "version": "3.10.3", 603 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.3.tgz", 604 | "integrity": "sha512-Lh00i69Uf6G74mvYpHCI9KVVXLcHW/xu79YTvH7Mkc9zyKUeSPz0owW0dguj0Scavns3ZOh3wY63J0Zb97Za2g==", 605 | "dev": true, 606 | "optional": true 607 | }, 608 | "util-deprecate": { 609 | "version": "1.0.2", 610 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 611 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 612 | }, 613 | "which": { 614 | "version": "1.2.14", 615 | "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", 616 | "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", 617 | "dev": true, 618 | "requires": { 619 | "isexe": "^2.0.0" 620 | } 621 | }, 622 | "wordwrap": { 623 | "version": "1.0.0", 624 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 625 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 626 | "dev": true 627 | }, 628 | "wrappy": { 629 | "version": "1.0.2", 630 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 631 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 632 | } 633 | } 634 | } 635 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jslint", 3 | "description": "The JavaScript Code Quality Tool", 4 | "homepage": "https://github.com/reid/node-jslint", 5 | "keywords": [ 6 | "lint", 7 | "jslint", 8 | "code-quality", 9 | "static-analysis", 10 | "jshint", 11 | "eslint" 12 | ], 13 | "version": "0.12.1", 14 | "author": "Reid Burke ", 15 | "contributors": [ 16 | "Douglas Crockford ", 17 | "Mikeal Rogers ", 18 | "Adam Moore", 19 | "Luke Smith ", 20 | "Anders Conbere ", 21 | "Ryuichi OKUMURA ", 22 | "Sam Mikes ", 23 | "Dylan Lloyd", 24 | "Andreas Hindborg", 25 | "Andrew Pennebaker", 26 | "Bnaya", 27 | "Maximilian Antoni ", 28 | "Vasil Velichkov", 29 | "Rasmus Paetau", 30 | "Bryan Horna" 31 | ], 32 | "bin": { 33 | "jslint": "./bin/jslint.js" 34 | }, 35 | "main": "./lib/nodelint.js", 36 | "dependencies": { 37 | "exit": "~0.1.2", 38 | "glob": "~7.1.3", 39 | "nopt": "~4.0.1", 40 | "readable-stream": "~2.1.5" 41 | }, 42 | "devDependencies": { 43 | "fs.extra": "^1.3.2", 44 | "istanbul": "~0.4.5", 45 | "marked-man": "~0.2.1", 46 | "mocha": "~5.2.0" 47 | }, 48 | "engines": { 49 | "node": ">=0.8.0" 50 | }, 51 | "files": [ 52 | "man/jslint.1", 53 | "doc/jslint.md", 54 | "doc/jslint.html", 55 | "lib", 56 | "bin", 57 | "jslint.conf.example", 58 | "Makefile" 59 | ], 60 | "directories": { 61 | "lib": "./lib", 62 | "man": "./man", 63 | "doc": "./doc" 64 | }, 65 | "man": "man/jslint.1", 66 | "repository": { 67 | "type": "git", 68 | "url": "git://github.com/reid/node-jslint.git" 69 | }, 70 | "bugs": { 71 | "url": "https://github.com/reid/node-jslint/issues" 72 | }, 73 | "license": "BSD-3-Clause", 74 | "licenses": [ 75 | { 76 | "type": "Modified MIT / BSD", 77 | "url": "https://github.com/reid/node-jslint/blob/master/LICENSE" 78 | } 79 | ], 80 | "scripts": { 81 | "test": "make test", 82 | "mypublish": "make prepublish; npm publish" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /test/color.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | color = require('../lib/color'); 3 | 4 | suite('text colors', function () { 5 | test('bold text', function () { 6 | assert.equal('\x1b[1mbold\x1b[0m', color.bold('bold')); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /test/fileopener.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | stream = require('stream'), 3 | FileOpener = require('../lib/fileopener.js'); 4 | 5 | suite('fileopener', function () { 6 | test('can create object', function () { 7 | var f = new FileOpener(); 8 | }); 9 | 10 | test('can open file', function (done) { 11 | var f = new FileOpener(); 12 | 13 | f.on('data', function(chunk) { 14 | done(); 15 | }); 16 | 17 | f.write('./README.md'); 18 | f.end(); 19 | }); 20 | 21 | test('error on nonexistent file', function (done) { 22 | var f = new FileOpener(); 23 | 24 | f.on('error', function(chunk) { 25 | done(); 26 | }); 27 | 28 | f.write('./NONEXISTENT-FILE.not-here'); 29 | f.end(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/fixtures/bad.js: -------------------------------------------------------------------------------- 1 | var __evil = eval( "3" ); 2 | -------------------------------------------------------------------------------- /test/fixtures/good.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function a(b) { 4 | return b + 1; 5 | } 6 | a(1); 7 | -------------------------------------------------------------------------------- /test/linter.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | nodelint = require('../lib/nodelint'), 3 | linter = require('../lib/linter'); 4 | 5 | suite('merge', function () { 6 | test('can merge when no conflict', function () { 7 | assert.deepEqual({a: 1, b: 2}, linter.merge({a: 1}, {b: 2})); 8 | }); 9 | 10 | test('left side wins on merge', function () { 11 | assert.deepEqual({a: 1}, linter.merge({a: 1}, {a: 2})); 12 | }); 13 | 14 | test('merge where one or more args is undefined', function () { 15 | assert.deepEqual({a: 1}, linter.merge({a: 1}, undefined)); 16 | 17 | assert.deepEqual({a: 1}, linter.merge(undefined, {a: 1})); 18 | }); 19 | 20 | test('merge where one object has inherited properties', function () { 21 | var util = require('util'); 22 | 23 | function A() { 24 | this.parent = 'overridden'; 25 | } 26 | 27 | function B() { 28 | this.own = 'overridden' 29 | } 30 | var c = { parent: 'orig', own: 'orig' }; 31 | 32 | util.inherits(B, A); 33 | 34 | assert.deepEqual({ parent: 'orig', own: 'overridden' }, 35 | linter.merge(new B(), c)); 36 | }); 37 | }); 38 | 39 | suite('preprocessScript', function () { 40 | test('removes leading BOM', function () { 41 | 42 | assert.equal('var x=1;', linter.preprocessScript('var x=1;')); 43 | 44 | assert.equal('var x=1;', linter.preprocessScript('\uFEFFvar x=1;')); 45 | 46 | }); 47 | test('removes shebang', function () { 48 | 49 | assert.equal('\nvar x=1;', linter.preprocessScript('#!/usr/bin/env node\nvar x=1;')); 50 | 51 | }); 52 | }); 53 | 54 | suite('lint', function () { 55 | var oldHome = process.env.HOME; 56 | teardown(function () { 57 | process.env.HOME = oldHome; 58 | }); 59 | 60 | test('basic lint step', function () { 61 | 62 | var script = "// only a comment\n", 63 | options = {edition: 'latest'}, 64 | JSLINT = nodelint.load(options.edition), 65 | result; 66 | 67 | // don't let user's config interfere with our test 68 | process.env.HOME = ''; 69 | 70 | result = linter.doLint(JSLINT, script, options); 71 | 72 | assert.deepEqual(result.errors, []); 73 | assert.ok(result.ok); 74 | }); 75 | 76 | test('lint finds error', function () { 77 | 78 | var script = "//TODO: remove this\n", 79 | options = {edition: '2013-09-22'}, 80 | JSLINT = nodelint.load(options.edition), 81 | result; 82 | 83 | // don't let user's config interfere with our test 84 | process.env.HOME = ''; 85 | 86 | result = linter.doLint(JSLINT, script, options); 87 | 88 | assert.strictEqual(1, result.errors.length); 89 | assert.strictEqual("Unexpected TODO comment.", 90 | result.errors[0].raw); 91 | 92 | }); 93 | 94 | test('maxerr causes null error', function () { 95 | var JSLINT = nodelint.load('lib/jslint-2013-09-22.js'), 96 | script = "var __evil = eval('3')", 97 | options = {maxerr: 1}, 98 | result; 99 | 100 | result = linter.doLint(JSLINT, script, options); 101 | 102 | assert.equal(result.ok, false); 103 | assert.equal(result.errors.length, 3); 104 | assert.equal(result.errors[2], null); 105 | 106 | }); 107 | 108 | 109 | }); 110 | -------------------------------------------------------------------------------- /test/lintstream.js: -------------------------------------------------------------------------------- 1 | // this file is test/lintstream.js 2 | // tests for stream interface to JSLint 3 | // 4 | // Copyright 2014 Cubane Canada Inc. 5 | // 6 | // Released under modified MIT/BSD 3-clause license 7 | // See LICENSE for details. 8 | 9 | var assert = require('assert'), 10 | stream = require('../lib/stream'), 11 | LintStream = require('../lib/lintstream.js'); 12 | 13 | suite('lintstream', function () { 14 | test('can create object', function () { 15 | var l = new LintStream(); 16 | 17 | assert.ok(l instanceof LintStream); 18 | assert.ok(l instanceof stream.Transform); 19 | }); 20 | 21 | test('can create object incorrectly', function () { 22 | var l = LintStream(); 23 | 24 | assert.ok(l instanceof LintStream); 25 | assert.ok(l instanceof stream.Transform); 26 | }); 27 | 28 | test('can lint a file', function (done) { 29 | var l = new LintStream(); 30 | 31 | l.on('data', function (chunk) { 32 | assert.equal(chunk.file, 'example.js'); 33 | 34 | assert.ok(chunk.linted.ok); 35 | assert.deepEqual(chunk.linted.errors, []); 36 | assert.deepEqual(chunk.linted.options, {}); 37 | 38 | done(); 39 | }); 40 | 41 | l.write({file: 'example.js', body: ''}); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/main.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | main; 3 | 4 | function mockConsole() { 5 | var c ={ 6 | warnings: [], 7 | warn: function(str) { 8 | c.warnings.push(str); 9 | }, 10 | loggings: [], 11 | log: function(str) { 12 | c.loggings.push(str); 13 | } 14 | }; 15 | 16 | return c; 17 | } 18 | 19 | function mockProcess() { 20 | var p = { 21 | argv: ['jslint'], 22 | exit: function (c) { 23 | this.exitCode = c; 24 | this.events.exit.forEach(function (f) { 25 | f(); 26 | }); 27 | }, 28 | doDrain: function() { 29 | this.events.drain.forEach(function (f) { 30 | f(); 31 | }); 32 | }, 33 | events: { exit: [], 34 | drain: [] }, 35 | on: function (event,f) { 36 | this.events[event].push(f); 37 | }, 38 | stdout: { 39 | isTTY: true, 40 | 41 | /* mock: call callback right away */ 42 | on: function (event, fn) { 43 | process.nextTick(function () { 44 | fn(); 45 | p.doDrain(); 46 | }); 47 | }, 48 | callbacks: { 49 | drain: [] 50 | } 51 | }, 52 | stderrWritings: [], 53 | stderr: { 54 | isTTY: true, 55 | 56 | /* mock: call callback right away */ 57 | write: function (string) { 58 | p.stderrWritings.push(string); 59 | } 60 | } 61 | }; 62 | return p; 63 | } 64 | 65 | function mockParsed() { 66 | return { 67 | argv: { 68 | remain: [] 69 | } 70 | }; 71 | } 72 | 73 | suite('jslint main', function () { 74 | var pro, con; 75 | 76 | setup(function () { 77 | main = require('../lib/main'); 78 | 79 | con = mockConsole(); 80 | pro = mockProcess(); 81 | 82 | main.setConsole(con); 83 | main.setProcess(pro); 84 | }); 85 | 86 | test('main - no args', function () { 87 | var parsed = mockParsed(); 88 | 89 | main.runMain(parsed); 90 | 91 | assert.ok(main); 92 | assert.strictEqual(1, pro.exitCode); 93 | assert.strictEqual(2, con.warnings.length); 94 | }); 95 | 96 | test('main - bad lint', function (done) { 97 | var parsed = mockParsed(); 98 | 99 | parsed.argv.remain.push('test/fixtures/bad.js'); 100 | 101 | main.runMain(parsed); 102 | 103 | pro.on('exit', function () { 104 | assert.equal(1, pro.exitCode); 105 | done(); 106 | }); 107 | }); 108 | 109 | 110 | test('main - glob files', function (done) { 111 | // bail if glob not installed 112 | if (!main.glob) { 113 | assert.ok(true); 114 | done(); 115 | return; 116 | } 117 | 118 | var parsed = mockParsed(); 119 | 120 | parsed.argv.remain.push('lib/mai*.js'); 121 | 122 | pro.on('exit', done); 123 | 124 | parsed.terse = true; 125 | 126 | main.runMain(parsed); 127 | 128 | assert.ok(main); 129 | }); 130 | 131 | test('main - glob ignore node_modules', function (done) { 132 | var parsed = mockParsed(); 133 | 134 | parsed.argv.remain.push('./lib/main.js'); 135 | parsed.argv.remain.push('./node_modules/glob/*'); 136 | 137 | parsed.filter = true; 138 | 139 | pro.on('exit', done); 140 | 141 | parsed.terse = true; 142 | 143 | main.runMain(parsed); 144 | 145 | assert.ok(main); 146 | }); 147 | 148 | test('main - glob --no-filter includes node_modules', function (done) { 149 | var parsed = mockParsed(); 150 | 151 | parsed.argv.remain.push('./lib/main.js'); 152 | parsed.argv.remain.push('./node_modules/glob/*.js'); 153 | 154 | parsed.filter = false; 155 | 156 | pro.on('exit', done); 157 | 158 | parsed.terse = true; 159 | 160 | main.runMain(parsed); 161 | 162 | assert.ok(main); 163 | }); 164 | 165 | test('main - one file, not tty, json output', function (done) { 166 | var parsed = mockParsed(); 167 | 168 | parsed.argv.remain.push('test/fixtures/good.js'); 169 | 170 | parsed.json = true; 171 | 172 | pro.stdout.isTTY = false; 173 | 174 | pro.on('exit', function () { 175 | assert.strictEqual(0, pro.exitCode); 176 | done(); 177 | }); 178 | 179 | main.runMain(parsed); 180 | 181 | assert.ok(main); 182 | 183 | // expect process.exit(0) to be as yet uncalled 184 | assert.strictEqual(undefined, pro.exitCode); 185 | }); 186 | 187 | test('todo in command-line options', function () { 188 | var o = main.commandOptions(); 189 | 190 | assert.strictEqual(Boolean, o.todo); 191 | }); 192 | 193 | function isBasicType(type, value) { 194 | return type(value).valueOf() === value; 195 | } 196 | 197 | test('isBasicType works', function () { 198 | 199 | assert.ok(isBasicType(Boolean, true)); 200 | assert.ok(isBasicType(Boolean, false)); 201 | assert.ok(isBasicType(Number, 1)); 202 | 203 | assert.ok(!isBasicType(Boolean, 0)); 204 | assert.ok(!isBasicType(Boolean, 1)); 205 | assert.ok(!isBasicType(Number, false)); 206 | assert.ok(!isBasicType(String, 1)); 207 | assert.ok(!isBasicType(Number, '1')); 208 | }); 209 | 210 | test('example jslint.conf contains only valid options', function (done) { 211 | 212 | var options = main.commandOptions(), 213 | fs = require('fs'); 214 | 215 | fs.readFile("jslint.conf.example", function (err, file) { 216 | if (err) { 217 | throw err; 218 | } 219 | 220 | var example = JSON.parse(file), 221 | keys = Object.keys(example); 222 | 223 | keys.forEach(function(opt) { 224 | assert.ok(options.hasOwnProperty(opt)); 225 | 226 | var type = options[opt], 227 | value = example[opt]; 228 | 229 | // skip predef because arrays are hard 230 | if (opt !== "predef") { 231 | assert.ok(isBasicType(type, value)); 232 | } 233 | }); 234 | 235 | done(); 236 | }); 237 | }); 238 | 239 | test('edition is a string (not Boolean) option', function () { 240 | var options = main.commandOptions(); 241 | 242 | assert.equal(String, options.edition); 243 | }); 244 | 245 | test('returns a version', function (done) { 246 | 247 | main.reportVersion(function (version) { 248 | 249 | assert.ok(/^node-jslint version:/.test(version)); 250 | assert.ok(/ JSLint edition/.test(version)); 251 | done(); 252 | }, {} ); 253 | }); 254 | 255 | test('argument parsing: edition is a string', function () { 256 | var options = main.parseArgs(['node', 'jslint', '--edition=latest']); 257 | 258 | assert.equal('latest', options.edition); 259 | }); 260 | 261 | test('argument parsing: can disable filter', function () { 262 | var options = main.parseArgs(['node', 'jslint', '--no-filter']); 263 | 264 | assert.equal(false, options.filter); 265 | }); 266 | 267 | test('main -- report version', function (done) { 268 | main.runMain({version: true}); 269 | 270 | done(); 271 | }); 272 | 273 | test('most data goes to console.log', function (done) { 274 | var rep = main.makeReporter({}); 275 | rep.on('finish', function () { 276 | assert.equal(con.loggings.length, 1); 277 | assert.equal(con.loggings[0], 'log message'); 278 | done(); 279 | }); 280 | rep.emit('data', 'log message'); 281 | rep.end(); 282 | }); 283 | 284 | test('dots go to process.stderr', function (done) { 285 | var rep = main.makeReporter({}); 286 | rep.on('finish', function () { 287 | assert.equal(pro.stderrWritings.length, 1); 288 | assert.equal(pro.stderrWritings[0], '.'); 289 | done(); 290 | }); 291 | rep.emit('data', '.'); 292 | rep.end(); 293 | }); 294 | 295 | test('quasi-programmatic interface', function (done) { 296 | var parsed = mockParsed(); 297 | 298 | parsed.argv.remain.push('test/fixtures/bad.js'); 299 | parsed.collector = true; 300 | 301 | main.runMain(parsed, function (err, report) { 302 | assert(report); 303 | done(); 304 | }); 305 | 306 | }); 307 | }); 308 | -------------------------------------------------------------------------------- /test/nodelint.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | nodelint = require('../lib/nodelint'); 3 | 4 | suite('jslint loader', function () { 5 | test('load implicit jslint', function () { 6 | var JSLINT = nodelint.load(); 7 | assert.ok(JSLINT); 8 | }); 9 | 10 | test('load explicit jslint', function () { 11 | var JSLINT = nodelint.load('latest'); 12 | assert.ok(JSLINT); 13 | }); 14 | 15 | test('load nonexistent jslint', function () { 16 | // mock console object 17 | var con = { warnings: [], 18 | warn: function(str) { 19 | this.warnings.push(str); 20 | } 21 | }; 22 | nodelint.setConsole(con); 23 | 24 | var JSLINT = nodelint.load('nonexistent'); 25 | assert.ok(JSLINT); 26 | 27 | // expect console warning 28 | assert.strictEqual(1, con.warnings.length); 29 | }); 30 | 31 | test('load by filename', function () { 32 | var JSLINT = nodelint.load('lib/jslint-2013-09-22.js'); 33 | 34 | assert.ok(JSLINT); 35 | assert.equal('2013-09-22', JSLINT.edition); 36 | }); 37 | 38 | test('looks like a filename', function () { 39 | var names = { 40 | 'foo': false, 41 | 'foo.js': true, 42 | 'foo/bar': true, 43 | 'foo\\bar': true 44 | }; 45 | 46 | Object.keys(names).forEach(function (n) { 47 | assert.equal(names[n], nodelint.looksLikeFileName(n)); 48 | }); 49 | }); 50 | 51 | }); 52 | -------------------------------------------------------------------------------- /test/options.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | options = require('../lib/options'); 3 | 4 | suite('addDefaults', function () { 5 | test('set node, es5 if unset', function () { 6 | assert.deepEqual({white: false, color: true, node: true, es5: true}, 7 | options.addDefaults({white: false, color: true})); 8 | }); 9 | 10 | test('explicit set prevents override', function () { 11 | assert.deepEqual({node: false, es5: false}, 12 | options.addDefaults({es5: false, node: false})); 13 | }); 14 | }); 15 | 16 | suite('splitPredefs', function () { 17 | test('can split predefs', function () { 18 | assert.deepEqual({predef: ['foo', 'bar', 'baz']}, 19 | options.splitPredefs({predef: "foo,bar,baz"})); 20 | }); 21 | test('doesnt re-split predefs', function () { 22 | assert.deepEqual({predef: ['foo', 'bar', 'baz']}, 23 | options.splitPredefs({predef: ['foo', 'bar', 'baz']})); 24 | }); 25 | }); 26 | 27 | suite('preprocessOptions', function() { 28 | test('accepts falsy options', function () { 29 | assert.deepEqual(options.preprocessOptions(undefined), options.preprocessOptions({})); 30 | }); 31 | }); 32 | 33 | suite('current dir config file', function () { 34 | var oldDir = process.cwd(), 35 | fs = require('fs.extra'), 36 | con; 37 | 38 | function mockConsole() { 39 | return { 40 | warnings: [], 41 | warn: function(str) { 42 | this.warnings.push(str); 43 | } 44 | }; 45 | } 46 | 47 | suiteSetup(function (done) { 48 | // mock console object 49 | con = mockConsole(); 50 | options.setConsole(con); 51 | 52 | fs.mkdir('test_config', function (err) { 53 | if (err) return done(err); 54 | process.chdir('test_config'); 55 | done(); 56 | }); 57 | }); 58 | 59 | suiteTeardown(function (done) { 60 | process.chdir(oldDir); 61 | fs.rmrf('test_config', function (err) { 62 | if (err) return done(err); 63 | done(); 64 | }); 65 | }); 66 | 67 | test('read jslintrc when present', function () { 68 | fs.writeFileSync('jslintrc', '{"foo": 1}'); 69 | 70 | assert.deepEqual({foo: 1}, options.loadAndParseConfig('jslintrc')); 71 | }); 72 | 73 | test('no crash when empty jslintrc', function () { 74 | fs.writeFileSync('jslintrc', ''); 75 | 76 | assert.deepEqual(undefined, options.loadAndParseConfig('jslintrc')); 77 | 78 | assert(/Error reading config file "jslintrc": SyntaxError: Unexpected end of /.test(con.warnings[0])); 79 | }); 80 | 81 | test('no crash when malformed jslintrc', function () { 82 | fs.writeFileSync('jslintrc', "{ 'invalid json': true"); 83 | 84 | assert.deepEqual(undefined, options.loadAndParseConfig('jslintrc')); 85 | 86 | assert(/Error reading config file "jslintrc": SyntaxError: Unexpected end of /.test(con.warnings[0])); 87 | }); 88 | 89 | test('nonexistent .jslintrc => undefined', function () { 90 | assert.deepEqual(undefined, options.loadAndParseConfig('.jslintrc')); 91 | }); 92 | 93 | test('merge global and local config correctly', function () { 94 | fs.writeFileSync('home', '{"foo": 1}'); 95 | fs.writeFileSync('local', '{"foo": 2}'); 96 | 97 | // no local = use home 98 | assert.deepEqual({foo: 1}, options.mergeConfigs(['home'], [])); 99 | 100 | // local overrides home 101 | assert.deepEqual({foo: 2}, options.mergeConfigs(['home'], ['local'])); 102 | 103 | // either branch of local overrides home 104 | assert.deepEqual({foo: 2}, options.mergeConfigs(['home'], ['filenotfound', 'local'])); 105 | }); 106 | 107 | test('load specific-named config files', function () { 108 | fs.writeFileSync('.jslintrc', '{"foo": "home"}'); 109 | fs.writeFileSync('jslintrc', '{"foo": "local"}'); 110 | 111 | // pretend current directory is home 112 | assert.deepEqual({foo: "local"}, options.loadConfig('.')); 113 | 114 | // Windows: process.env.HOME can be unset (undefined) 115 | assert.deepEqual({foo: "local"}, options.loadConfig(undefined)); 116 | }); 117 | 118 | test('load user-named config files', function () { 119 | fs.writeFileSync('user.jslint.conf', '{"bar": "user"}'); 120 | 121 | // pretend current directory is home 122 | var conf = options.loadConfig('.', './user.jslint.conf'); 123 | 124 | assert.equal("user", conf.bar); 125 | 126 | }); 127 | }); 128 | -------------------------------------------------------------------------------- /test/regression.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | nodelint = require('../lib/nodelint'), 3 | linter = require('../lib/linter'); 4 | 5 | suite('case #101', function () { 6 | // https://github.com/reid/node-jslint/issues/101 7 | test('has warning with default options', function () { 8 | 9 | var options = {edition: 'latest'}, 10 | JSLINT = nodelint.load(options.edition), 11 | script = "console.log('a');\n", 12 | result = linter.doLint(JSLINT, script, options); 13 | 14 | assert.ok(!result.ok); 15 | }); 16 | 17 | test('no warning with node option', function () { 18 | 19 | var options = {edition: 'latest', node: true}, 20 | JSLINT = nodelint.load(options.edition), 21 | script = "console.log('a');\n", 22 | result = linter.doLint(JSLINT, script, options); 23 | 24 | assert.ok(result.ok); 25 | }); 26 | 27 | test('use es6 linter', function () { 28 | 29 | var options = {edition: 'es6', node: true}, 30 | JSLINT = nodelint.load(options.edition), 31 | script = "console.log('a');\n", 32 | result = linter.doLint(JSLINT, script, options); 33 | 34 | assert.ok(result); 35 | }); 36 | 37 | test('post-es6 versions report edition', function (done) { 38 | var options = {edition: '2015-05-08'}, 39 | main = require('../lib/main'); 40 | 41 | main.reportVersion(function (version) { 42 | assert.ok(/^node-jslint version:/.test(version)); 43 | assert.ok(/ JSLint edition 2015-05-08/.test(version)); 44 | done(); 45 | }, options ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/reporter.js: -------------------------------------------------------------------------------- 1 | var reporter = require('../lib/reporter'), 2 | assert = require('assert'); 3 | 4 | suite('reporter', function () { 5 | 'use strict'; 6 | var log, 7 | errorLint = { 8 | ok: false, 9 | errors: [ 10 | err(1, 1, "Fake error 1."), 11 | err(2, 3, "Fake error 2.", "Fake evidence") 12 | ] 13 | }, 14 | es6ErrorLint = { 15 | ok: false, 16 | errors: [ { line: 0, 17 | column: 3, 18 | message: "foo" } ], 19 | lines: [ "this is an evidence line" ] 20 | }, 21 | es6Fudged = { 22 | ok: false, 23 | errors: [ { line: 0, 24 | column: 3, 25 | message: "foo" } ], 26 | option: { fudge: 1 }, 27 | lines: [ "this is an evidence line" ] 28 | }; 29 | 30 | 31 | 32 | 33 | function err(l, c, r, e) { 34 | var err = { 35 | line: l, 36 | character: c, 37 | reason: r 38 | }; 39 | if(e) { 40 | err.evidence=e; 41 | } 42 | return err; 43 | }; 44 | 45 | function newLog() { 46 | var o = { 47 | outLines: [], 48 | errLines: [] 49 | }; 50 | 51 | o.log = o.outLines.push.bind(o.outLines); 52 | o.err = o.errLines.push.bind(o.errLines); 53 | 54 | return o; 55 | } 56 | 57 | setup(function () { 58 | log = newLog(); 59 | reporter.setLogger(log); 60 | }); 61 | 62 | test('lint OK, no color, no terse', function () { 63 | reporter.report('example.js', {ok: true}, false, false); 64 | 65 | assert.deepEqual(1, log.outLines.length); 66 | assert.deepEqual("\nexample.js is OK.", log.outLines[0]); 67 | }); 68 | 69 | test('lint OK, no color, terse', function () { 70 | reporter.report('example.js', {ok: true}, false, true); 71 | 72 | assert.deepEqual(1, log.errLines.length); 73 | assert.deepEqual(".", log.errLines[0]); 74 | }); 75 | 76 | test('lint OK, color, no terse', function () { 77 | reporter.report('example.js', {ok: true}, true, false); 78 | 79 | assert.deepEqual(1, log.outLines.length); 80 | assert.notEqual(-1, log.outLines[0].search(/OK/)); 81 | }); 82 | 83 | test('lint bad, no color, no terse', function () { 84 | reporter.report('example.js', errorLint, false, false); 85 | 86 | assert.deepEqual(5, log.outLines.length); 87 | assert.equal(-1, log.outLines[0].search(/OK/)); 88 | 89 | assert.deepEqual([ 90 | '\nexample.js', 91 | ' #1 Fake error 1.', 92 | ' // Line 1, Pos 1', 93 | ' #2 Fake error 2.', 94 | ' Fake evidence // Line 2, Pos 3' 95 | ], log.outLines); 96 | 97 | }); 98 | 99 | test('lint bad, no color, terse', function () { 100 | reporter.report('example.js', errorLint, false, true); 101 | 102 | assert.deepEqual(2, log.outLines.length); 103 | assert.equal(-1, log.outLines[0].search(/OK/)); 104 | 105 | assert.deepEqual([ 106 | 'example.js:1:1: Fake error 1.', 107 | 'example.js:2:3: Fake error 2.' 108 | ], log.outLines); 109 | 110 | }); 111 | 112 | test('lint bad, color, no terse', function () { 113 | reporter.report('example.js', errorLint, true, false); 114 | 115 | assert.deepEqual(5, log.outLines.length); 116 | assert.equal(-1, log.outLines[0].search(/OK/)); 117 | 118 | // no assertion re content: just force exercise of color branch 119 | }); 120 | 121 | test('lint bad, es6 format', function () { 122 | reporter.report('example.js', es6ErrorLint, true, false); 123 | }); 124 | 125 | test('fudge fudges output', function (done) { 126 | var reporter = require('../lib/reporter.js'); 127 | 128 | reporter.report('example.js', es6Fudged, false, true); 129 | 130 | assert.deepEqual(1, log.outLines.length); 131 | assert.equal(log.outLines[0], 'example.js:1:4: foo'); 132 | done(); 133 | }); 134 | 135 | }); 136 | -------------------------------------------------------------------------------- /test/reportstream.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | stream = require('../lib/stream'), 3 | ReportStream = require('../lib/reportstream.js'), 4 | JSONReportStream = require('../lib/jsonreportstream.js'), 5 | CollectorStream = require('../lib/collectorstream.js'); 6 | 7 | suite('reportstream', function () { 8 | test('can create object', function () { 9 | var r = new ReportStream(); 10 | 11 | assert.ok(r instanceof ReportStream); 12 | assert.ok(r instanceof stream.Transform); 13 | }); 14 | 15 | test('can create object incorrectly', function () { 16 | var r = ReportStream(); 17 | 18 | assert.ok(r instanceof ReportStream); 19 | assert.ok(r instanceof stream.Transform); 20 | }); 21 | 22 | test('can async', function (done) { 23 | var r = new ReportStream(); 24 | 25 | r.on('data', function(chunk) { 26 | assert.deepEqual(chunk, '\nexample.js is OK.'); 27 | done(); 28 | }); 29 | 30 | r.write({file: 'example.js', linted: {ok: true}}); 31 | r.end(); 32 | }); 33 | 34 | test('can make a colorized reporter', function (done) { 35 | var r = new ReportStream({color: true}); 36 | 37 | r.on('data', function(chunk) { 38 | assert.deepEqual(chunk, '\n\x1b[1mexample.js\x1b[0m is \x1b[32mOK\x1b[0m.'); 39 | done(); 40 | }); 41 | 42 | r.write({file: 'example.js', linted: {ok: true}}); 43 | r.end(); 44 | }); 45 | 46 | test('can make a terse reporter', function (done) { 47 | var r = new ReportStream({terse: true}); 48 | 49 | r.on('data', function(chunk) { 50 | assert.deepEqual(chunk, '.'); 51 | done(); 52 | }); 53 | 54 | r.write({file: 'example.js', linted: {ok: true}}); 55 | r.end(); 56 | }); 57 | 58 | test('can make two reporters with diff. behavior', function (done) { 59 | var r1 = new ReportStream(), 60 | r2 = new ReportStream({terse: true}); 61 | 62 | r1.on('data', function (chunk) { 63 | r2.write({file: 'example.js', linted: {ok: true}}); 64 | r2.end(); 65 | }); 66 | r2.on('data', function (chunk) { 67 | assert.equal(chunk, '.'); 68 | done(); 69 | }); 70 | 71 | r1.write({file: 'example.js', linted: {ok: true}}); 72 | r1.end(); 73 | }); 74 | 75 | test('how about a JSONReportStream', function (done) { 76 | var r = new JSONReportStream(); 77 | 78 | r.on('data', function (chunk) { 79 | assert.deepEqual(chunk, JSON.stringify(['example.js', null])); 80 | done(); 81 | }); 82 | 83 | r.write({file: 'example.js', linted: {ok: true}}); 84 | r.end(); 85 | }); 86 | 87 | test('incorrectly construct a JSONReportStream', function (done) { 88 | var r = JSONReportStream(); 89 | 90 | assert.ok(r instanceof JSONReportStream); 91 | assert.ok(r instanceof stream.Transform); 92 | done(); 93 | }); 94 | }); 95 | 96 | suite('collectorstream', function () { 97 | test('can create object', function () { 98 | var r = new CollectorStream(); 99 | 100 | assert.ok(r instanceof CollectorStream); 101 | assert.ok(r instanceof stream.Transform); 102 | }); 103 | 104 | test('can create object incorrectly', function () { 105 | var r = CollectorStream(); 106 | 107 | assert.ok(r instanceof CollectorStream); 108 | assert.ok(r instanceof stream.Transform); 109 | }); 110 | }); 111 | --------------------------------------------------------------------------------