├── .gitignore ├── .gitmodules ├── .travis.yml ├── Makefile ├── README.md ├── config.js ├── doc └── nodelint.md ├── examples └── emacs │ └── flymake-nodelint.el ├── lib └── reporters │ ├── default.js │ ├── idea.js │ ├── index.js │ ├── table.js │ ├── textmate_full.js │ ├── textmate_summary.js │ ├── vim.js │ └── xml.js ├── man1 └── nodelint.1 ├── nodelint ├── package.json └── test ├── fixtures ├── browser-4-space-indent.js ├── no-errors.js ├── node-2-space-indent.js ├── node-4-space-indent.js ├── nodejs-predefines.js └── some-errors.js.nolint ├── helper.js ├── test-dir-and-file.js ├── test-lint-code.js ├── test-multiple-files.js ├── test-nodejs-predefines.js ├── test-reporters-no-errors.js ├── test-reporters-some-errors.js └── test-single-file.js /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore temp files 2 | *~ 3 | .*.swp 4 | .DS_Store 5 | dist/ 6 | stamp-build 7 | stamp-dependencies 8 | stamp-devdependencies 9 | # ignore IDE files 10 | .idea 11 | .project 12 | .settings 13 | # ignore node_modules 14 | node_modules -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "jslint"] 2 | path = jslint 3 | url = https://github.com/douglascrockford/JSLint 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | - 0.10 5 | - 0.11 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | PACKAGE = nodelint 3 | NODEJS = $(if $(shell test -f /usr/bin/nodejs && echo "true"),nodejs,node) 4 | 5 | PREFIX ?= /usr/local 6 | BINDIR ?= $(PREFIX)/bin 7 | DATADIR ?= $(PREFIX)/share 8 | MANDIR ?= $(PREFIX)/share/man 9 | LIBDIR ?= $(PREFIX)/lib 10 | ETCDIR = /etc 11 | PACKAGEDATADIR ?= $(DATADIR)/$(PACKAGE) 12 | 13 | BUILDDIR = dist 14 | 15 | $(shell if [ ! -d $(BUILDDIR) ]; then mkdir $(BUILDDIR); fi) 16 | 17 | DOCS = $(shell find doc -name '*.md' \ 18 | |sed 's|.md|.1|g' \ 19 | |sed 's|doc/|man1/|g' \ 20 | ) 21 | 22 | all: build doc 23 | 24 | build: stamp-build 25 | 26 | stamp-build: dependencies jslint/jslint.js nodelint config.js 27 | touch stamp-build; 28 | cp $^ $(BUILDDIR); 29 | perl -pi -e 's{^\s*SCRIPT_DIRECTORY =.*?\n}{}ms' $(BUILDDIR)/nodelint 30 | perl -pi -e 's{path\.join\(SCRIPT_DIRECTORY, '\''config.js'\''\)}{"$(ETCDIR)/nodelint.conf"}' $(BUILDDIR)/nodelint 31 | perl -pi -e 's{path\.join\(SCRIPT_DIRECTORY, '\''jslint/jslint\.js'\''\)}{"$(PACKAGEDATADIR)/jslint.js"}' $(BUILDDIR)/nodelint 32 | 33 | install: build doc 34 | install --directory $(PACKAGEDATADIR) 35 | install --mode 0644 $(BUILDDIR)/jslint.js $(PACKAGEDATADIR)/jslint.js 36 | install --mode 0644 $(BUILDDIR)/config.js $(ETCDIR)/nodelint.conf 37 | install --mode 0755 $(BUILDDIR)/nodelint $(BINDIR)/nodelint 38 | install --directory $(MANDIR)/man1/ 39 | cp -a man1/nodelint.1 $(MANDIR)/man1/ 40 | 41 | uninstall: 42 | rm -rf $(PACKAGEDATADIR)/jslint.js $(ETCDIR)/nodelint.conf $(BINDIR)/nodelint 43 | rm -rf $(MANDIR)/man1/nodelint.1 44 | 45 | clean: 46 | rm -rf $(BUILDDIR) stamp-build 47 | 48 | dependencies: stamp-dependencies 49 | 50 | stamp-dependencies: 51 | touch stamp-dependencies; 52 | npm install 53 | git submodule update --init --recursive 54 | 55 | devdependencies: dependencies stamp-devdependencies 56 | 57 | stamp-devdependencies: 58 | touch stamp-devdependencies; 59 | touch stamp-dependencies; 60 | npm install --dev 61 | 62 | test: devdependencies 63 | ./node_modules/.bin/nodeunit ./test/test-*.js 64 | 65 | lint: devdependencies 66 | ./nodelint ./nodelint ./config.js ./lib/ ./test/ 67 | 68 | lint-package-json: devdependencies 69 | ./nodelint ./package.json 70 | 71 | doc: devdependencies man1 $(DOCS) 72 | @true 73 | 74 | man1: 75 | @if ! test -d man1 ; then mkdir -p man1 ; fi 76 | 77 | # use `npm install ronn` for this to work. 78 | man1/%.1: doc/%.md 79 | ./node_modules/.bin/ronn --roff $< > $@ 80 | 81 | .PHONY: test install uninstall build all 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | nodelint 2 | -------- 3 | 4 | - [Node.js] is a [V8] based framework for writing Javascript applications outside 5 | the browser. 6 | 7 | - [JSLint] is a code quality tool that checks for problems in Javascript programs. 8 | 9 | - **nodelint** lets you run JSLint from the command line. 10 | 11 | - nodelint currently supports node version 0.4.x and tested with 0.5.9 so should run on 0.6.x 12 | 13 | [Node.js]: http://nodejs.org/ 14 | [V8]: http://code.google.com/p/v8/ 15 | [JSLint]: https://github.com/douglascrockford/JSLint 16 | 17 | 18 | installation 19 | ------------ 20 | 21 | npm: 22 | 23 | $ npm install nodelint 24 | 25 | 26 | If you clone nodelint from Github, you should init JSLint submodule: 27 | 28 | $ git submodule update --init 29 | 30 | 31 | usage 32 | ----- 33 | 34 | You can use `nodelint` directly if you have `node` in your $PATH, 35 | or if you installed it using `npm -g`: 36 | 37 | $ nodelint path/to/your/file.js 38 | 39 | Otherwise, you need to run it with node: 40 | 41 | $ node path/to/nodelint path/to/your/file.js 42 | 43 | You can also specify a directory param and nodelint will find all .js files under that directory and its subdirectories: 44 | 45 | $ node path/to/nodelint dir1/ dir2/ 46 | 47 | Enjoy! 48 | 49 | 50 | configuration 51 | ------------- 52 | 53 | You can override default JSLint options by passing config file with the optional `--config` parameter: 54 | 55 | $ nodelint file1 file2 dir1 dir2 --config path/to/your/config/file.js 56 | 57 | For example, if the default config.js has: 58 | 59 | var options = { 60 | adsafe : false, 61 | bitwise : true, 62 | ... 63 | "predef" : [] 64 | }; 65 | 66 | And your own path/to/your/config/file.js looks like: 67 | 68 | var options = { 69 | bitwise : false, 70 | browser : false 71 | }; 72 | 73 | Then the final options used will be: 74 | 75 | var options = { 76 | adsafe : false, 77 | bitwise : false, 78 | browser : false, 79 | ... 80 | "predef" : [] 81 | }; 82 | 83 | Take a look at [JSLint's options] to see what to put in the `options` variable. 84 | 85 | [JSLint's options]: http://www.jslint.com/lint.html#options 86 | 87 | You can also add your configuration inside the JS files itself: 88 | JSLint will use this one instead of the global one. 89 | 90 | Simply add some comments at the beginning of the file. 91 | Note that there is no space between /* and global and between /* and jslint: 92 | 93 | // define your global objects: 94 | /*global YUI, JQuery */ 95 | 96 | // define your jslint-options: 97 | /*jslint white: true, onevar: true, undef: true, nomen: true */ 98 | 99 | 100 | reporters 101 | --------- 102 | 103 | By default nodelint uses an internal `reporter` to output it's results to the console. 104 | There may be times when a more customizable reporting system might be needed 105 | (*i.e. IDE/Text Editor integrations or customized console outputs*). 106 | 107 | `nodelint` allows you to designate a custom reporter for outputting the results 108 | from JSLint's run. This `reporter` will override the default one 109 | built into nodelint. To utilize a custom reporter first create a js file that 110 | exports `reporter` function: 111 | 112 | `example-reporter.js`: 113 | 114 | var util = require('util'); 115 | 116 | function report(results) { 117 | var len = results.length; 118 | util.puts(len + ' error' + ((len === 1) ? '' : 's')); 119 | } 120 | 121 | exports.report = report; 122 | 123 | Then when you run nodelint from the command line, pass in the customized 124 | reporter: 125 | 126 | `$ ./nodelint path/to/file.js --reporter path/to/file/example-reporter.js` 127 | 128 | For brevity sake, this is a fairly simple reporter. 129 | 130 | `nodelint` includes some build-in reportes for VIM, Textmate and JetBrains IDEA integration. 131 | 132 | Also it include XML reporter, that produces reports which can 133 | also be integrated with a Continuous Integration server like [Hudson] using the 134 | [Violations Plugin]. 135 | 136 | Please see the [wiki][wiki] for integration with various editors. 137 | 138 | [Hudson]: http://hudson-ci.org 139 | [Violations Plugin]: http://wiki.hudson-ci.org/display/HUDSON/Violations 140 | 141 | 142 | contribute 143 | ---------- 144 | 145 | To contribute any patches, simply fork this repository using GitHub and send a 146 | pull request to me <>. Thanks! 147 | 148 | 149 | credits 150 | ------- 151 | 152 | - [tav], wrote nodelint 153 | 154 | - [Felix Geisendörfer][felixge], clarified Node.js specific details 155 | 156 | - [Douglas Crockford], wrote the original JSLint and rhino.js runner 157 | 158 | - [Nathan Landis][my8bird], updated nodelint to Node's new API. 159 | 160 | - [Oleg Efimov][Sannis], added support for overridable configurations, running 161 | nodelint from a symlink and updates to reflect Node.js API changes. 162 | 163 | - [Matthew Kitt][mkitt], added support for configurable reporters, various code 164 | cleanups and improvements including updates to reflect Node.js API changes. 165 | 166 | - [Corey Hart], updated nodelint with multiple files and config support. 167 | 168 | - [Mamading Ceesay][evangineer], added support for using nodelint within Emacs. 169 | 170 | - [Matt Ranney][mranney], updated nodelint to use sys.error. 171 | 172 | - [Cliffano Subagio], added npm installation support, XML reporter, and directory param support. 173 | 174 | - [Clemens Akens], updated to latest JSLint from Crockford repo 175 | 176 | - [Paul Armstrong], updates to reflect Node.js and npm API changes 177 | 178 | [tav]: http://tav.espians.com 179 | [felixge]: http://debuggable.com 180 | [Douglas Crockford]: http://www.crockford.com 181 | [my8bird]: http://github.com/my8bird 182 | [Sannis]: http://github.com/Sannis 183 | [mkitt]: http://github.com/mkitt 184 | [Corey Hart]: http://www.codenothing.com 185 | [evangineer]: http://github.com/evangineer 186 | [mranney]: http://github.com/mranney 187 | [Cliffano Subagio]: http://blog.cliffano.com 188 | [Clemens Akens]: https://github.com/clebert 189 | [Paul Armstrong]: https://github.com/paularmstrong 190 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This is the default options file for nodelint 3 | * 4 | * Changes released into the Public Domain by tav 5 | * Options support added by Corey Hart 6 | */ 7 | 8 | /*jslint indent: 4*/ 9 | 10 | var options = { 11 | anon: false, // if the space may be omitted in anonymous function declarations 12 | bitwise: true, // if bitwise operators should be allowed 13 | browser: false, // if the standard browser globals should be predefined 14 | cap: false, // if upper case HTML should be allowed 15 | 'continue': false, // if the continuation statement should be tolerated 16 | css: false, // if CSS workarounds should be tolerated 17 | debug: false, // if debugger statements should be allowed 18 | devel: false, // if logging should be allowed (console, alert, etc.) 19 | eqeq: false, // if == should be allowed 20 | es5: false, // if ES5 syntax should be allowed 21 | evil: false, // if eval should be allowed 22 | forin: false, // if for in statements need not filter 23 | fragment: false, // if HTML fragments should be allowed 24 | indent: 2, // the indentation factor 25 | maxerr: 50, // the maximum number of errors to allow 26 | maxlen: 100, // the maximum length of a source line 27 | newcap: false, // if constructor names capitalization is ignored 28 | node: true, // if Node.js globals should be predefined 29 | nomen: true, // if names may have dangling _ 30 | on: false, // if HTML event handlers should be allowed 31 | passfail: false, // if the scan should stop on first error 32 | plusplus: true, // if increment/decrement should be allowed 33 | properties: false, // if all property names must be declared with /*properties*/ 34 | regexp: true, // if the . should be allowed in regexp literals // TODO: fix this later 35 | rhino: false, // if the Rhino environment globals should be predefined 36 | undef: false, // if variables can be declared out of order 37 | unparam: false, // if unused parameters should be tolerated 38 | sloppy: true, // if the 'use strict'; pragma is optional // TODO: fix this later 39 | stupid: true, // if really stupid practices are tolerated // TODO: fix this later 40 | sub: false, // if all forms of subscript notation are tolerated 41 | vars: false, // if multiple var statements per function should be allowed 42 | white: false, // if sloppy whitespace is tolerated 43 | widget: false, // if the Yahoo Widgets globals should be predefined 44 | windows: false, // if MS Windows-specific globals should be predefined 45 | 46 | // the names of predefined global variables: 47 | "predef": [] 48 | }; 49 | -------------------------------------------------------------------------------- /doc/nodelint.md: -------------------------------------------------------------------------------- 1 | nodelint(1) -- Run JSLint from the command-line under node.js 2 | ============================================================= 3 | 4 | ## SYNOPSIS 5 | 6 | nodelint [options] [ ...] 7 | 8 | ## DESCRIPTION 9 | 10 | The nodelint command-line tool allows you to check for problems and ensure 11 | the code quality of your JavaScript files using JSLint. 12 | 13 | It is completely extensible so you can use your own custom JSLint config or 14 | even use custom reporters that better integrate with your quality assurance 15 | framework. 16 | 17 | ## OPTIONS 18 | 19 | __--reporter FILE__: 20 | Override the default reporter with your own custom module. See 21 | the *examples/reporters* directory for custom reporters that come 22 | bundled with nodelint. 23 | 24 | __--config FILE__: 25 | Override the default *config.js* with your own config file. 26 | 27 | __-h__, __--help__: 28 | Display the help and exit. 29 | 30 | __-v__, __--version__: 31 | Output version information and exit. 32 | 33 | ____: 34 | You can run nodelint on specific files or on all *\*.js* files inside 35 | a directory. 36 | 37 | ## CONFIG 38 | 39 | You can customise the JSLint options by modifying the default config.js 40 | file or by providing your own config file with the *--config* parameter: 41 | 42 | nodelint --config path/to/custom.js file1.js file2.js ... 43 | 44 | For example, if the default config.js looks like: 45 | 46 | var options = { 47 | adsafe : false, 48 | bitwise : true 49 | }; 50 | 51 | And your custom.js looks like: 52 | 53 | var options = { 54 | bitwise : false, 55 | browser : false 56 | }; 57 | 58 | Then the final options will be: 59 | 60 | var options = { 61 | adsafe : false, 62 | bitwise : false, 63 | browser : false 64 | }; 65 | 66 | ## JSLINT OPTIONS 67 | 68 | * adsafe: 69 | True if ADsafe rules should be enforced. See http://www.ADsafe.org/. 70 | * bitwise: 71 | True if bitwise operators should not be allowed. 72 | * browser: 73 | True if the standard browser globals should be predefined. 74 | * cap: 75 | True if upper case HTML should be allowed. 76 | * css: 77 | True if CSS workarounds should be tolerated. 78 | * debug: 79 | True if debugger statements should be allowed. 80 | Set this option to false before going into production. 81 | * devel: 82 | True if browser globals that are useful in development 83 | (console, alert, ...) should be predefined. 84 | * eqeqeq: 85 | True if === should be required. 86 | * es5: 87 | True if ES5 syntax should be allowed. 88 | * evil: 89 | True if eval should be allowed. 90 | * forin: 91 | True if unfiltered for in statements should be allowed. 92 | * fragment: 93 | True if HTML fragments should be allowed. 94 | * immed: 95 | True if immediate function invocations must be wrapped in parens 96 | * indent: 97 | The number of spaces used for indentation (default is 4) 98 | * laxbreak: 99 | True if statement breaks should not be checked. 100 | * maxerr: 101 | The maximum number of warnings reported (default is 50) 102 | * maxlen: 103 | The maximum number of characters in a line 104 | * nomen: 105 | True if names should be checked for initial or trailing underbars 106 | * newcap: 107 | True if Initial Caps must be used with constructor functions. 108 | * on: 109 | True if HTML event handlers should be allowed. 110 | * onevar: 111 | True if only one var statement per function should be allowed. 112 | * passfail: 113 | True if the scan should stop on first error. 114 | * plusplus: 115 | True if ++ and -- should not be allowed. 116 | * predef: 117 | An array of strings (comma separated), the names of predefined global variables. 118 | predef is used with the option object, but not with the /*jslint */ comment. 119 | Use the var statement to declare global variables in a script file. 120 | * regexp: 121 | True if . and [^...] should not be allowed in RegExp literals. 122 | These forms should not be used when validating in secure applications. 123 | * rhino: 124 | True if the Rhino environment globals should be predefined. 125 | * safe: 126 | True if the safe subset rules are enforced. These rules are used by ADsafe. 127 | It enforces the safe subset rules but not the widget structure rules. 128 | * strict: 129 | True if the ES5 "use strict"; pragma is required. Do not use this option carelessly. 130 | * sub: 131 | True if subscript notation may be used for expressions better expressed in dot notation. 132 | * undef: 133 | True if variables must be declared before used. 134 | * white: 135 | True if strict whitespace rules apply. 136 | * widget: 137 | True if the Yahoo Widgets globals should be predefined. 138 | * windows: 139 | True if the Windows globals should be predefined. 140 | 141 | 142 | ## AUTHORS 143 | 144 | Written by Tav and other nodelint contributors. 145 | Contributors list: . 146 | 147 | ## REPORTING BUGS 148 | 149 | Report nodelint bugs to . 150 | 151 | ## COPYRIGHT 152 | 153 | Nodelint has been released into the Public Domain by its Authors. 154 | 155 | ## SEE ALSO 156 | 157 | node(1) 158 | 159 | -------------------------------------------------------------------------------- /examples/emacs/flymake-nodelint.el: -------------------------------------------------------------------------------- 1 | ;; On-the-fly syntax checking of javascript using nodelint to run JSLint. 2 | ;; 3 | ;; Changes to this file have been released into the Public Domain. 4 | ;; Adapted from http://www.emacswiki.org/emacs/FlymakeJavaScript 5 | ;; 6 | ;; Installation: 7 | ;; 8 | ;; Put this in your load-path, then add the following to your .emacs. 9 | ;; You substitude espresso-mode-hook for javascript-mode-hook if you 10 | ;; use espresso or js2-mode-hook if using js2-mode. 11 | ;; 12 | ;; (require 'flymake-nodelint) 13 | ;; (add-hook 'javascript-mode-hook 14 | ;; (lambda () (flymake-mode t))) 15 | ;; 16 | ;; Make sure env can find node in your $PATH 17 | 18 | (require 'flymake) 19 | 20 | (setq flymake-log-level 3) 21 | 22 | (defun flymake-nodelint-init () 23 | (let* ((temp-file (flymake-init-create-temp-buffer-copy 24 | 'flymake-create-temp-inplace)) 25 | (local-file (file-relative-name 26 | temp-file 27 | (file-name-directory buffer-file-name)))) 28 | (list "nodelint" (list local-file)))) 29 | 30 | ;; needs debugging 31 | (setq flymake-allowed-file-name-masks 32 | (cons '(".+\\.js$" 33 | flymake-nodelint-init 34 | flymake-simple-cleanup 35 | flymake-get-real-file-name) 36 | flymake-allowed-file-name-masks)) 37 | 38 | ;; using this in lieu of the above 39 | ;;(eval-after-load "flymake" 40 | ;; '(progn 41 | ;; (add-to-list 'flymake-allowed-file-name-masks 42 | ;; '("\\.js\\'" flymake-nodelint-init)))) 43 | 44 | (setq flymake-err-line-patterns 45 | (cons '("^Lint at line \\([[:digit:]]+\\) character \\([[:digit:]]+\\): \\(.+\\)$" 46 | nil 1 2 3) 47 | flymake-err-line-patterns)) 48 | 49 | (add-hook 'find-file-hook 'flymake-find-file-hook) 50 | 51 | (provide 'flymake-nodelint) 52 | 53 | -------------------------------------------------------------------------------- /lib/reporters/default.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint default reporter 3 | * 4 | * Released into the Public Domain by tav 5 | * See the README.md for full credits of the awesome contributors! 6 | */ 7 | 8 | /** 9 | * Module dependencies 10 | */ 11 | var util = require('util'); 12 | 13 | /** 14 | * Reporter info string 15 | */ 16 | exports.info = "Default reporter"; 17 | 18 | /** 19 | * Should we use ANSI coloring? 20 | * Credits Coffeescript Cakefile 21 | */ 22 | var enableColors = false; 23 | if (process.platform !== 'win32') { 24 | enableColors = (process.env.NODE_DISABLE_COLORS === "1") ? false : true; 25 | } 26 | 27 | /** 28 | * Customise the error reporting -- the following colours the text red if enableColors 29 | */ 30 | var 31 | errorPrefix = enableColors ? "\u001b[1;31m" : "", 32 | errorSuffix = enableColors ? "\u001b[0m" : ""; 33 | 34 | /** 35 | * Report linting results to the command-line. 36 | * 37 | * @api public 38 | * 39 | * @param {Array} results 40 | */ 41 | exports.report = function report(results) { 42 | var 43 | error_regexp = /^\s*(\S*(\s+\S+)*)\s*$/, 44 | i, 45 | len = results.length, 46 | str = '', 47 | error; 48 | 49 | for (i = 0; i < len; i += 1) { 50 | error = results[i].error; 51 | str += errorPrefix + results[i].file + ', line ' + error.line + 52 | ', character ' + error.character + ":" + errorSuffix + " " + 53 | error.reason + '\n' + 54 | (error.evidence || '').replace(error_regexp, "$1") + '\n'; 55 | } 56 | 57 | str += len + ' error' + ((len === 1) ? '' : 's'); 58 | 59 | util.puts(str); 60 | }; 61 | -------------------------------------------------------------------------------- /lib/reporters/idea.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint IDEA reporter 3 | * 4 | * Reporter for working with external tools within the Idea IDEs 5 | * Only tested with RubyMine 6 | * For setup instructions see: https://github.com/tav/nodelint/wiki/Editor-and-IDE-integration 7 | * 8 | * Released into the Public Domain by tav 9 | * See the README.md for full credits of the awesome contributors! 10 | */ 11 | 12 | /** 13 | * Module dependencies 14 | */ 15 | var util = require('util'); 16 | 17 | /** 18 | * Reporter info string 19 | */ 20 | exports.info = "IDEA reporter"; 21 | 22 | /** 23 | * Report linting results to the command-line. 24 | * 25 | * @api public 26 | * 27 | * @param {Array} results 28 | */ 29 | exports.report = function report(results) { 30 | var 31 | error_regexp = /^\s*(\S*(\s+\S+)*)\s*$/, 32 | i, 33 | len = results.length, 34 | str = '', 35 | file, 36 | error; 37 | 38 | if (len > 0) { 39 | for (i = 0; i < len; i += 1) { 40 | file = results[i].file; 41 | error = results[i].error; 42 | 43 | str += file + ' ' + error.line + 44 | ':' + error.character + 45 | ' ' + error.reason + ' ' + 46 | (error.evidence || '').replace(error_regexp, "$1"); 47 | } 48 | util.puts(str); 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /lib/reporters/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'default': require('./default'), 3 | 'idea': require('./idea'), 4 | 'table': require('./table'), 5 | 'textmate_full': require('./textmate_full'), 6 | 'textmate_summary': require('./textmate_summary'), 7 | 'vim': require('./vim'), 8 | 'xml': require('./xml') 9 | }; 10 | -------------------------------------------------------------------------------- /lib/reporters/table.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint Table reporter 3 | * 4 | * Reporter for outputing errors as a table at the command line. 5 | * 6 | * Released into the Public Domain by Phani 7 | * See the README.md for full credits of the awesome contributors! 8 | */ 9 | 10 | /** 11 | * Module dependencies 12 | */ 13 | var _ = require('underscore'), 14 | CliTable = require('cli-table'); 15 | 16 | /** 17 | * Reporter info string 18 | */ 19 | exports.info = "Table reporter"; 20 | 21 | /** 22 | * Report linting results to the command-line as a table. 23 | * 24 | * @api public 25 | * 26 | * @param {Array} results 27 | */ 28 | exports.report = function report(results) { 29 | var len = results.length, 30 | groupedResults = _.groupBy(results, function (error) { 31 | return error.file; 32 | }); 33 | _.each(groupedResults, function (fileErrors, index) { 34 | var table = new CliTable({ 35 | head: ['Line', 'Character', 'Reason'], 36 | colWidths: [10, 15, 150] 37 | }); 38 | console.log(' %s , total errors (%s)', index, groupedResults[index].length); 39 | _.each(groupedResults[index], function (result) { 40 | var row = []; 41 | row.push(result.error.line); 42 | row.push(result.error.character); 43 | row.push(result.error.reason); 44 | table.push(row); 45 | }); 46 | 47 | console.log(table.toString()); 48 | }); 49 | 50 | if (len > 0) { 51 | console.log('total errors : (%s)', len); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /lib/reporters/textmate_full.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint Textmate full HTML reporter 3 | * 4 | * Outputs to a TextMate HTML window printing JSLint results. 5 | * 6 | * The Command: 7 | * . "$TM_SUPPORT_PATH/lib/webpreview.sh" 8 | * html_header "JSLint Results" 9 | * node "/path/to/nodelint/nodelint" "$TM_FILEPATH" \ 10 | * --config "$TM_BUNDLE_SUPPORT/bin/path/to/config.js" \ 11 | * --reporter "$TM_BUNDLE_SUPPORT/bin/path/to/full_reporter.js" 12 | * 13 | * Invoked by "⌃⇧V" 14 | * @author Matthew Kitt 15 | * 16 | * For setup instructions see: https://github.com/tav/nodelint/wiki/Editor-and-IDE-integration 17 | * 18 | * Released into the Public Domain by tav 19 | * See the README.md for full credits of the awesome contributors! 20 | */ 21 | 22 | /** 23 | * Module dependencies 24 | */ 25 | var util = require('util'); 26 | 27 | /** 28 | * Reporter info string 29 | */ 30 | exports.info = "Textmate full HTML reporter"; 31 | 32 | /** 33 | * Report linting results to the command-line. 34 | * 35 | * @api public 36 | * 37 | * @param {Array} results 38 | */ 39 | exports.report = function report(results) { 40 | var 41 | error_regexp = /^\s*(\S*(\s+\S+)*)\s*$/, 42 | i, 43 | len = results.length, 44 | output = '', 45 | html = '', 46 | file, 47 | error, 48 | reason, 49 | line, 50 | character; 51 | 52 | for (i = 0; i < len; i += 1) { 53 | file = results[i].file; 54 | error = results[i].error; 55 | reason = error.reason; 56 | line = error.line; 57 | character = error.character; 58 | output += '
  • ' + 59 | '' + 61 | '' + reason + '' + 62 | ' line ' + line + 63 | ', character ' + character + '' + 64 | '' + 65 | '
    ' +
    66 |                   (error.evidence || '').replace(error_regexp, "$1") +
    67 |                 '
    ' + 68 | '
  • '; 69 | } 70 | 71 | html += '' + 72 | '' + 73 | '' + 83 | '' + 84 | '' + 85 | '

    ' + len + ' Error' + ((len === 1) ? '' : 's') + '

    ' + 86 | '
    ' + 87 | '
      ' + 88 | output + 89 | '
    ' + 90 | '' + 91 | ''; 92 | 93 | util.puts(html); 94 | }; 95 | -------------------------------------------------------------------------------- /lib/reporters/textmate_summary.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint Textmate summary reporter 3 | * 4 | * Runs JSLint on a TextMate save through a source.js file. 5 | * If there is 1-2 errors it will print out the results through a tooltip. 6 | * If there are more than 5 errors it will only print out a summary. 7 | * If there are no errors, nothing will happen. 8 | * 9 | * The Command: 10 | * node "/path/to/nodelint/nodelint" "$TM_FILEPATH" \ 11 | * --config "$TM_BUNDLE_SUPPORT/bin/path/to/config.js" \ 12 | * --reporter "$TM_BUNDLE_SUPPORT/bin/path/to/summary_reporter.js" 13 | * 14 | * Invoked by "⌘S" 15 | * @author Matthew Kitt 16 | * 17 | * For setup instructions see: https://github.com/tav/nodelint/wiki/Editor-and-IDE-integration 18 | * 19 | * Released into the Public Domain by tav 20 | * See the README.md for full credits of the awesome contributors! 21 | */ 22 | 23 | /** 24 | * Module dependencies 25 | */ 26 | var util = require('util'); 27 | 28 | /** 29 | * Reporter info string 30 | */ 31 | exports.info = "Textmate full HTML reporter"; 32 | 33 | /** 34 | * Report linting results to the command-line. 35 | * 36 | * @api public 37 | * 38 | * @param {Array} results 39 | */ 40 | exports.report = function report(results) { 41 | var 42 | len = results.length, 43 | output = '', 44 | getOutput = function () { 45 | var 46 | error_regexp = /^\s*(\S*(\s+\S+)*)\s*$/, 47 | i, 48 | len = results.length, 49 | output = '', 50 | file, 51 | error; 52 | 53 | for (i = 0; i < len; i += 1) { 54 | file = results[i].file; 55 | file = file.substring(file.lastIndexOf('/') + 1, file.length); 56 | error = results[i].error; 57 | 58 | output += file + ': line ' + error.line + 59 | ', character ' + error.character + ', ' + 60 | error.reason + '\n' + 61 | (error.evidence || '').replace(error_regexp, "$1") + '\n\n'; 62 | } 63 | return output; 64 | }; 65 | 66 | if (len > 0 && len < 2) { 67 | output += getOutput(); 68 | } 69 | output += len + ' error' + ((len === 1) ? '' : 's'); 70 | 71 | if (len > 0) { 72 | util.puts(output); 73 | } 74 | }; 75 | -------------------------------------------------------------------------------- /lib/reporters/vim.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint VIM syntastic reporter 3 | * 4 | * Reporter for working with the vim syntastic plugin 5 | * See http://gist.github.com/629349 for the vim script 6 | * 7 | * Released into the Public Domain by tav 8 | * See the README.md for full credits of the awesome contributors! 9 | */ 10 | 11 | /** 12 | * Module dependencies 13 | */ 14 | var util = require('util'); 15 | 16 | /** 17 | * Reporter info string 18 | */ 19 | exports.info = "VIM syntastic reporter"; 20 | 21 | /** 22 | * Report linting results to the command-line. 23 | * 24 | * @api public 25 | * 26 | * @param {Array} results 27 | */ 28 | exports.report = function report(results) { 29 | var 30 | error_regexp = /^\s*(\S*(\s+\S+)*)\s*$/, 31 | i, 32 | len = results.length, 33 | str = '', 34 | file, 35 | error; 36 | 37 | if (len > 0) { 38 | for (i = 0; i < len; i += 1) { 39 | file = results[i].file; 40 | error = results[i].error; 41 | 42 | str += file + 'line ' + error.line + 43 | ' column ' + error.character + 44 | ' Error: ' + error.reason + ' ' + 45 | (error.evidence || '').replace(error_regexp, "$1"); 46 | 47 | str += (i === len - 1) ? '' : '\n'; 48 | } 49 | util.puts(str); 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /lib/reporters/xml.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint XML reporter 3 | * 4 | * This reporter produces XML that can be automatically recognised by 5 | * Hudson Violations Plugin http://wiki.hudson-ci.org/display/HUDSON/Violations+Plugin 6 | * 7 | * Released into the Public Domain by tav 8 | * See the README.md for full credits of the awesome contributors! 9 | */ 10 | 11 | /** 12 | * Module dependencies 13 | */ 14 | var 15 | path = require('path'), 16 | util = require('util'); 17 | 18 | /** 19 | * Reporter info string 20 | */ 21 | exports.info = "XML reporter"; 22 | 23 | function escape(str) { 24 | return (str) ? str 25 | .replace(/&/g, '&') 26 | .replace(//g, '>') 28 | .replace(/"/g, '"') 29 | : ''; 30 | } 31 | 32 | /** 33 | * Report linting results to the command-line. 34 | * 35 | * @api public 36 | * 37 | * @param {Array} results 38 | */ 39 | exports.report = function report(results) { 40 | var 41 | i, error, len, file, 42 | dir = process.cwd(), 43 | xml = '\n\n'; 44 | 45 | for (i = 0, len = results.length; i < len; i += 1) { 46 | file = path.resolve(dir, results[i].file); 47 | error = results[i].error; 48 | xml += '\t\n' + 49 | '\t\t\n' + 51 | '\t\n'; 52 | } 53 | 54 | xml += ''; 55 | 56 | util.puts(xml); 57 | }; 58 | -------------------------------------------------------------------------------- /man1/nodelint.1: -------------------------------------------------------------------------------- 1 | .\" Generated with Ronnjs 0.3.8 2 | .\" http://github.com/kapouer/ronnjs/ 3 | . 4 | .TH "NODELINT" "1" "March 2012" "" "" 5 | . 6 | .SH "NAME" 7 | \fBnodelint\fR \-\- Run JSLint from the command\-line under node\.js 8 | . 9 | .SH "SYNOPSIS" 10 | . 11 | .nf 12 | nodelint [options] [ \.\.\.] 13 | . 14 | .fi 15 | . 16 | .SH "DESCRIPTION" 17 | The nodelint command\-line tool allows you to check for problems and ensure 18 | . 19 | .br 20 | the code quality of your JavaScript files using JSLint\. 21 | . 22 | .P 23 | It is completely extensible so you can use your own custom JSLint config or 24 | . 25 | .br 26 | even use custom reporters that better integrate with your quality assurance 27 | . 28 | .br 29 | framework\. 30 | . 31 | .SH "OPTIONS" 32 | \fB\-\-reporter FILE\fR: 33 | . 34 | .br 35 | Override the default reporter with your own custom module\. See 36 | . 37 | .br 38 | the \fIexamples/reporters\fR directory for custom reporters that come 39 | . 40 | .br 41 | bundled with nodelint\. 42 | . 43 | .P 44 | \fB\-\-config FILE\fR: 45 | . 46 | .br 47 | Override the default \fIconfig\.js\fR with your own config file\. 48 | . 49 | .P 50 | \fB\-h\fR, \fB\-\-help\fR: 51 | . 52 | .br 53 | Display the help and exit\. 54 | . 55 | .P 56 | \fB\-v\fR, \fB\-\-version\fR: 57 | . 58 | .br 59 | Output version information and exit\. 60 | . 61 | .P 62 | \fB\fR: 63 | You can run nodelint on specific files or on all \fI*\.js\fR files inside 64 | . 65 | .br 66 | a directory\. 67 | . 68 | .SH "CONFIG" 69 | You can customise the JSLint options by modifying the default config\.js 70 | . 71 | .br 72 | file or by providing your own config file with the \fI\-\-config\fR parameter: 73 | . 74 | .IP "" 4 75 | . 76 | .nf 77 | nodelint \-\-config path/to/custom\.js file1\.js file2\.js \.\.\. 78 | . 79 | .fi 80 | . 81 | .IP "" 0 82 | . 83 | .P 84 | For example, if the default config\.js looks like: 85 | . 86 | .IP "" 4 87 | . 88 | .nf 89 | var options = { 90 | adsafe : false, 91 | bitwise : true 92 | }; 93 | . 94 | .fi 95 | . 96 | .IP "" 0 97 | . 98 | .P 99 | And your custom\.js looks like: 100 | . 101 | .IP "" 4 102 | . 103 | .nf 104 | var options = { 105 | bitwise : false, 106 | browser : false 107 | }; 108 | . 109 | .fi 110 | . 111 | .IP "" 0 112 | . 113 | .P 114 | Then the final options will be: 115 | . 116 | .IP "" 4 117 | . 118 | .nf 119 | var options = { 120 | adsafe : false, 121 | bitwise : false, 122 | browser : false 123 | }; 124 | . 125 | .fi 126 | . 127 | .IP "" 0 128 | . 129 | .SH "JSLINT OPTIONS" 130 | . 131 | .IP "\(bu" 4 132 | adsafe: 133 | . 134 | .br 135 | True if ADsafe rules should be enforced\. See http://www\.ADsafe\.org/\. 136 | . 137 | .IP "\(bu" 4 138 | bitwise: 139 | . 140 | .br 141 | True if bitwise operators should not be allowed\. 142 | . 143 | .IP "\(bu" 4 144 | browser: 145 | . 146 | .br 147 | True if the standard browser globals should be predefined\. 148 | . 149 | .IP "\(bu" 4 150 | cap: 151 | . 152 | .br 153 | True if upper case HTML should be allowed\. 154 | . 155 | .IP "\(bu" 4 156 | css: 157 | . 158 | .br 159 | True if CSS workarounds should be tolerated\. 160 | . 161 | .IP "\(bu" 4 162 | debug: 163 | . 164 | .br 165 | True if debugger statements should be allowed\. 166 | . 167 | .br 168 | Set this option to false before going into production\. 169 | . 170 | .IP "\(bu" 4 171 | devel: 172 | . 173 | .br 174 | True if browser globals that are useful in development 175 | . 176 | .br 177 | (console, alert, \.\.\.) should be predefined\. 178 | . 179 | .IP "\(bu" 4 180 | eqeqeq: 181 | . 182 | .br 183 | True if === should be required\. 184 | . 185 | .IP "\(bu" 4 186 | es5: 187 | . 188 | .br 189 | True if ES5 syntax should be allowed\. 190 | . 191 | .IP "\(bu" 4 192 | evil: 193 | . 194 | .br 195 | True if eval should be allowed\. 196 | . 197 | .IP "\(bu" 4 198 | forin: 199 | . 200 | .br 201 | True if unfiltered for in statements should be allowed\. 202 | . 203 | .IP "\(bu" 4 204 | fragment: 205 | . 206 | .br 207 | True if HTML fragments should be allowed\. 208 | . 209 | .IP "\(bu" 4 210 | immed: 211 | . 212 | .br 213 | True if immediate function invocations must be wrapped in parens 214 | . 215 | .IP "\(bu" 4 216 | indent: 217 | . 218 | .br 219 | The number of spaces used for indentation (default is 4) 220 | . 221 | .IP "\(bu" 4 222 | laxbreak: 223 | . 224 | .br 225 | True if statement breaks should not be checked\. 226 | . 227 | .IP "\(bu" 4 228 | maxerr: 229 | . 230 | .br 231 | The maximum number of warnings reported (default is 50) 232 | . 233 | .IP "\(bu" 4 234 | maxlen: 235 | . 236 | .br 237 | The maximum number of characters in a line 238 | . 239 | .IP "\(bu" 4 240 | nomen: 241 | . 242 | .br 243 | True if names should be checked for initial or trailing underbars 244 | . 245 | .IP "\(bu" 4 246 | newcap: 247 | . 248 | .br 249 | True if Initial Caps must be used with constructor functions\. 250 | . 251 | .IP "\(bu" 4 252 | on: 253 | . 254 | .br 255 | True if HTML event handlers should be allowed\. 256 | . 257 | .IP "\(bu" 4 258 | onevar: 259 | . 260 | .br 261 | True if only one var statement per function should be allowed\. 262 | . 263 | .IP "\(bu" 4 264 | passfail: 265 | . 266 | .br 267 | True if the scan should stop on first error\. 268 | . 269 | .IP "\(bu" 4 270 | plusplus: 271 | . 272 | .br 273 | True if ++ and \-\- should not be allowed\. 274 | . 275 | .IP "\(bu" 4 276 | predef: 277 | . 278 | .br 279 | An array of strings (comma separated), the names of predefined global variables\. 280 | . 281 | .br 282 | predef is used with the option object, but not with the /\fIjslint \fR/ comment\. 283 | . 284 | .br 285 | Use the var statement to declare global variables in a script file\. 286 | . 287 | .IP "\(bu" 4 288 | regexp: 289 | . 290 | .br 291 | True if \. and [^\.\.\.] should not be allowed in RegExp literals\. 292 | . 293 | .br 294 | These forms should not be used when validating in secure applications\. 295 | . 296 | .IP "\(bu" 4 297 | rhino: 298 | . 299 | .br 300 | True if the Rhino environment globals should be predefined\. 301 | . 302 | .IP "\(bu" 4 303 | safe: 304 | . 305 | .br 306 | True if the safe subset rules are enforced\. These rules are used by ADsafe\. 307 | . 308 | .br 309 | It enforces the safe subset rules but not the widget structure rules\. 310 | . 311 | .IP "\(bu" 4 312 | strict: 313 | . 314 | .br 315 | True if the ES5 "use strict"; pragma is required\. Do not use this option carelessly\. 316 | . 317 | .IP "\(bu" 4 318 | sub: 319 | . 320 | .br 321 | True if subscript notation may be used for expressions better expressed in dot notation\. 322 | . 323 | .IP "\(bu" 4 324 | undef: 325 | . 326 | .br 327 | True if variables must be declared before used\. 328 | . 329 | .IP "\(bu" 4 330 | white: 331 | . 332 | .br 333 | True if strict whitespace rules apply\. 334 | . 335 | .IP "\(bu" 4 336 | widget: 337 | . 338 | .br 339 | True if the Yahoo Widgets globals should be predefined\. 340 | . 341 | .IP "\(bu" 4 342 | windows: 343 | . 344 | .br 345 | True if the Windows globals should be predefined\. 346 | . 347 | .IP "" 0 348 | . 349 | .SH "AUTHORS" 350 | Written by Tav and other nodelint contributors\. 351 | . 352 | .br 353 | Contributors list: \fIhttps://github\.com/tav/nodelint/contributors\fR\|\. 354 | . 355 | .SH "REPORTING BUGS" 356 | Report nodelint bugs to \fIhttps://github\.com/tav/nodelint/issues\fR\|\. 357 | . 358 | .SH "COPYRIGHT" 359 | Nodelint has been released into the Public Domain by its Authors\. 360 | . 361 | .SH "SEE ALSO" 362 | node(1) 363 | -------------------------------------------------------------------------------- /nodelint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* vim:set ft=javascript ts=8 sw=4 tw=0 : */ 3 | 4 | /* 5 | * nodelint -- a command line JSLint runner under node.js 6 | * 7 | * Released into the Public Domain by tav 8 | * See the README.md for full credits of the awesome contributors! 9 | */ 10 | 11 | /*global JSLINT, options */ 12 | /*jslint evil: true */ 13 | 14 | (function () { 15 | var 16 | f = require('file'), 17 | fs = require('fs'), 18 | path = require('path'), 19 | util = require('util'), 20 | SCRIPT_DIRECTORY, 21 | DEFAULT_CONFIG_FILE, 22 | params, 23 | files, 24 | config_file, 25 | config_param_found, 26 | reporter_file = 'default', 27 | reporter_param_found, 28 | builtin_reporters = require(__dirname + '/lib/reporters'), 29 | reporter, 30 | usage = 31 | "Usage: nodelint file.js [file2 file3 ...] [options]\n" + 32 | "Options:\n\n" + 33 | " --config FILE the path to a config.js file with JSLINT options\n" + 34 | " --reporter FILE optional path to a reporter.js file to customize the output\n" + 35 | " --list-reporters list available build-in reporters\n" + 36 | " -h, --help display this help and exit\n" + 37 | " -v, --version output version information and exit"; 38 | 39 | // ----------------------------------------------------------------------------- 40 | // load jslint itself and set the path to the default config file 41 | // ----------------------------------------------------------------------------- 42 | 43 | SCRIPT_DIRECTORY = path.dirname(fs.realpathSync(__filename)); 44 | DEFAULT_CONFIG_FILE = path.join(SCRIPT_DIRECTORY, 'config.js'); 45 | 46 | eval(fs.readFileSync(path.join(SCRIPT_DIRECTORY, 'jslint/jslint.js'), 'utf8')); 47 | 48 | // ----------------------------------------------------------------------------- 49 | // skript main funktion 50 | // ----------------------------------------------------------------------------- 51 | 52 | function lint(files, default_config_file, config_file, reporter) { 53 | var 54 | retval = 0, 55 | results = [], 56 | option_name, 57 | real_options; 58 | 59 | if (!files.length) { 60 | util.puts(usage); 61 | return 1; 62 | } 63 | 64 | eval(fs.readFileSync(default_config_file, 'utf8')); 65 | 66 | if (typeof options === 'undefined') { 67 | util.puts("Error: there's no `options` variable in the default config file."); 68 | return 1; 69 | } 70 | 71 | real_options = options; 72 | 73 | if (typeof config_file !== 'undefined') { 74 | eval(fs.readFileSync(config_file, 'utf8')); 75 | 76 | if (typeof options === 'undefined') { 77 | util.puts("Error: there's no `options` variable in the config file."); 78 | return 1; 79 | } 80 | 81 | for (option_name in options) { 82 | if (options.hasOwnProperty(option_name)) { 83 | real_options[option_name] = options[option_name]; 84 | } 85 | } 86 | } 87 | 88 | files.forEach(function (file) { 89 | var 90 | source, 91 | i, 92 | error, 93 | // Quite enougth config clone, may be improved in future 94 | current_file_options = JSON.parse(JSON.stringify(real_options)); 95 | 96 | try { 97 | source = fs.readFileSync(file, 'utf8'); 98 | } catch (err) { 99 | util.puts("Error: Opening file <" + file + ">"); 100 | util.puts(err + '\n'); 101 | retval = 1; 102 | return; 103 | } 104 | 105 | // remove any shebangs 106 | source = source.replace(/^\#\!.*/, ''); 107 | 108 | if (!JSLINT(source, current_file_options)) { 109 | for (i = 0; i < JSLINT.errors.length; i += 1) { 110 | error = JSLINT.errors[i]; 111 | if (error) { 112 | results.push({file: file, error: error}); 113 | } 114 | } 115 | retval = 2; 116 | } 117 | }); 118 | 119 | reporter.report(results, real_options); 120 | 121 | return retval; 122 | } 123 | 124 | // ----------------------------------------------------------------------------- 125 | // run the file as a script if called directly, i.e. not imported via require() 126 | // ----------------------------------------------------------------------------- 127 | 128 | params = process.argv.splice(2); 129 | files = []; 130 | 131 | // a very basic pseudo --options parser 132 | params.forEach(function (param) { 133 | var content, pkg, stat, reporter_file_for_forin_loop; 134 | if (param.slice(0, 9) === "--config=") { 135 | config_file = param.slice(9); 136 | } else if (param === '--config') { 137 | config_param_found = true; 138 | } else if (config_param_found) { 139 | config_file = param; 140 | config_param_found = false; 141 | } else if (param.slice(0, 11) === "--reporter=") { 142 | reporter_file = param.slice(11); 143 | } else if (param === '--reporter') { 144 | reporter_param_found = true; 145 | } else if (reporter_param_found) { 146 | reporter_file = param; 147 | reporter_param_found = false; 148 | } else if (param === '--list-reporters') { 149 | util.puts('Build-in reporters: '); 150 | for (reporter_file_for_forin_loop in builtin_reporters) { 151 | if (builtin_reporters.hasOwnProperty(reporter_file_for_forin_loop)) { 152 | if (builtin_reporters[reporter_file_for_forin_loop].info) { 153 | util.puts(' * ' + reporter_file_for_forin_loop 154 | + ': ' + builtin_reporters[reporter_file_for_forin_loop].info); 155 | } else { 156 | util.puts(' * ' + reporter_file_for_forin_loop); 157 | } 158 | } 159 | } 160 | process.exit(0); 161 | } else if ((param === '--version') || (param === '-v')) { 162 | content = fs.readFileSync(path.join(SCRIPT_DIRECTORY, 'package.json'), 'utf8'); 163 | pkg = JSON.parse(content); 164 | util.puts(pkg.version); 165 | process.exit(0); 166 | } else if ((param === '--help') || (param === '-h')) { 167 | util.puts(usage); 168 | process.exit(0); 169 | } else { 170 | stat = fs.statSync(param); 171 | if (stat.isDirectory()) { 172 | f.walkSync(param, function (base, dirs, names) { 173 | names.forEach(function (name) { 174 | if (name.match(/.js$/)) { 175 | files.push(path.join(base, name)); 176 | } 177 | }); 178 | }); 179 | } else { 180 | files.push(param); 181 | } 182 | } 183 | }); 184 | 185 | // Get reporter by name or by file 186 | if (builtin_reporters.hasOwnProperty(reporter_file)) { 187 | reporter = builtin_reporters[reporter_file]; 188 | } else { 189 | reporter = require(reporter_file); 190 | } 191 | 192 | process.exit(lint(files, DEFAULT_CONFIG_FILE, config_file, reporter)); 193 | 194 | }()); 195 | 196 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodelint", 3 | "description": "The nodelint command line tool allows you to check for problems using JSLint. You can specify your own --config file to use alternate JSLint options and your own --reporter file if you want to customise the generated output.", 4 | "keywords": ["lint", "jslint", "nodelint", "code quality"], 5 | "version": "0.6.2", 6 | "homepage": "https://github.com/tav/nodelint", 7 | "author": "tav (https://tav.espians.com)", 8 | "maintainers": [ 9 | "tav ", 10 | "cliffano ", 11 | "Sannis " 12 | ], 13 | "contributors": [ 14 | "Matthew Kitt (https://github.com/mkitt)", 15 | "Oleg Efimov (https://github.com/Sannis)", 16 | "Corey Hart (http://www.codenothing.com)", 17 | "Cliffano Subagio (http://blog.cliffano.com)", 18 | "Mamading Ceesay (https://github.com/evangineer)", 19 | "Matt Ranney (https://github.com/mranney)", 20 | "Felix Geisendörfer (http://debuggable.com)", 21 | "Nathan Landis (https://github.com/my8bird)", 22 | "Clemens Akens (https://github.com/clebert)" 23 | ], 24 | "repository": { 25 | "type": "git", 26 | "url": "git://github.com/tav/nodelint.git" 27 | }, 28 | "bugs": { "url": "https://github.com/tav/nodelint/issues" }, 29 | "bin": { 30 | "nodelint": "./nodelint" 31 | }, 32 | "directories": { "doc": "./doc", "man": "./man1" }, 33 | "dependencies": { 34 | "file": ">=0.2.0", 35 | "underscore" : "x", 36 | "cli-table" : "x" 37 | }, 38 | "devDependencies": { 39 | "nodeunit": ">=0.6.2", 40 | "ronn": ">=0.3.7" 41 | }, 42 | "engines": { "node": ">=0.4" }, 43 | "scripts": { 44 | "test": "make test", 45 | "prepublish" : "make doc" 46 | }, 47 | "licenses": { 48 | "type": "Public Domain" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/fixtures/browser-4-space-indent.js: -------------------------------------------------------------------------------- 1 | /*jslint indent: 4, node: false, browser: true*/ 2 | 3 | var userAgent = navigator.userAgent; 4 | 5 | function getOrCreate(tag, id) { 6 | var el = document.getElementById(id); 7 | if (!el) { 8 | el = document.createElement(tag); 9 | el.id = id; 10 | document.body.appendChild(el); 11 | } 12 | return el; 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/no-errors.js: -------------------------------------------------------------------------------- 1 | function someRightFunction() { 2 | var a = 2, b = a + 1; 3 | console.log(a + b); 4 | process.exit(777); 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/node-2-space-indent.js: -------------------------------------------------------------------------------- 1 | function someFunction() { 2 | var a = 5; 3 | console.log(a); 4 | process.exit(1234); 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/node-4-space-indent.js: -------------------------------------------------------------------------------- 1 | /*jslint indent: 4*/ 2 | 3 | function someFunction() { 4 | var a = 5; 5 | console.log(a); 6 | process.exit(1234); 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/nodejs-predefines.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | function someFunction() { 4 | var buffer = new Buffer(128); 5 | 6 | setInterval(); 7 | 8 | clearInterval(setInterval(function () { 9 | return; 10 | }, 1000)); 11 | 12 | clearTimeout(setTimeout(function () { 13 | return; 14 | }, 1000)); 15 | } 16 | 17 | exports.someFunction = someFunction; 18 | 19 | console.log(module.filename === __filename); 20 | 21 | console.log(__filename); 22 | 23 | console.log(__dirname); 24 | 25 | console.log(typeof global); 26 | 27 | console.log(process.pid); 28 | 29 | -------------------------------------------------------------------------------- /test/fixtures/some-errors.js.nolint: -------------------------------------------------------------------------------- 1 | var 2 | a = 1, 3 | b = 2; 4 | 5 | if (a = b) { 6 | console.log("Hehe"); 7 | } 8 | -------------------------------------------------------------------------------- /test/helper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint tests helper 3 | * 4 | * Released into the Public Domain by tav 5 | * See the README.md for full credits of the awesome contributors! 6 | */ 7 | 8 | /** 9 | * Module dependencies 10 | */ 11 | var childProcess = require('child_process'); 12 | 13 | var node_deprecated_warning = "The \"sys\" module is now called \"util\". " 14 | + "It should have a similar interface.\n"; 15 | 16 | /** 17 | * Helper for console run output test 18 | */ 19 | function testConsoleOutput(file, args, options, expected, test) { 20 | if (typeof test === 'undefined') { 21 | test = expected; 22 | expected = options; 23 | options = null; 24 | } 25 | 26 | childProcess.execFile(file, args, options, function (error, stdout, stderr) { 27 | var testsCount = 0; 28 | if (expected.hasOwnProperty('exitCode')) { 29 | testsCount += 1; // error.code || !error 30 | } 31 | if (expected.hasOwnProperty('exitSignal')) { 32 | testsCount += 1; // error 33 | testsCount += 1; // error.signal 34 | } 35 | if (expected.hasOwnProperty('stdout')) { 36 | testsCount += 1; // stdout 37 | } 38 | if (expected.hasOwnProperty('stderr')) { 39 | testsCount += 1; // stderr 40 | } 41 | 42 | test.expect(testsCount); 43 | 44 | if (expected.hasOwnProperty('exitCode')) { 45 | if (expected.exitCode === 0) { 46 | test.equals(error, null); 47 | } else { 48 | test.equals(error.code, expected.exitCode); 49 | } 50 | } 51 | if (expected.hasOwnProperty('exitSignal')) { 52 | test.ok(error instanceof Error); 53 | test.equals(error.signal, expected.exitSignal); 54 | } 55 | if (expected.hasOwnProperty('stdout')) { 56 | test.equals(stdout.replace(node_deprecated_warning, ''), expected.stdout); 57 | } 58 | if (expected.hasOwnProperty('stderr')) { 59 | test.equals(stderr.replace(node_deprecated_warning, ''), expected.stderr); 60 | } 61 | 62 | test.done(); 63 | }); 64 | } 65 | 66 | exports.testConsoleOutput = testConsoleOutput; 67 | -------------------------------------------------------------------------------- /test/test-dir-and-file.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint tests for both files and directories 3 | * 4 | * Released into the Public Domain by tav 5 | * See the README.md for full credits of the awesome contributors! 6 | */ 7 | 8 | /** 9 | * Module dependencies 10 | */ 11 | var helper = require('./helper'); 12 | 13 | /** 14 | * Test for both files and directories 15 | * 16 | * @param test 17 | */ 18 | exports.DirAndFile = function (test) { 19 | helper.testConsoleOutput( 20 | './nodelint', 21 | [ 22 | __dirname + '/fixtures/', 23 | __dirname + '/test-dir-and-file.js' 24 | ], 25 | { 26 | stdout: '0 errors\n', 27 | stderr: '', 28 | exitCode: 0 29 | }, 30 | test 31 | ); 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /test/test-lint-code.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint code style test 3 | * 4 | * Released into the Public Domain by tav 5 | * See the README.md for full credits of the awesome contributors! 6 | */ 7 | 8 | /** 9 | * Module dependencies 10 | */ 11 | var helper = require('./helper'); 12 | 13 | /** 14 | * Lint nodelint own code 15 | * 16 | * @param test 17 | */ 18 | exports.MakeLint = function (test) { 19 | helper.testConsoleOutput( 20 | './nodelint', 21 | ['./nodelint', './config.js', './lib/', './test/'], 22 | { 23 | stdout: '0 errors\n', 24 | stderr: '', 25 | exitCode: 0 26 | }, 27 | test 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /test/test-multiple-files.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint tests for multiple files linting 3 | * 4 | * Released into the Public Domain by tav 5 | * See the README.md for full credits of the awesome contributors! 6 | */ 7 | 8 | /** 9 | * Module dependencies 10 | */ 11 | var helper = require('./helper'); 12 | 13 | /** 14 | * Test for multiple files linting 15 | * 16 | * @param test 17 | */ 18 | exports.VariousIndents = function (test) { 19 | helper.testConsoleOutput( 20 | './nodelint', 21 | [ 22 | __dirname + '/fixtures/node-4-space-indent.js', 23 | __dirname + '/fixtures/node-2-space-indent.js', 24 | __dirname + '/fixtures/node-4-space-indent.js' 25 | ], 26 | { 27 | stdout: '0 errors\n', 28 | stderr: '', 29 | exitCode: 0 30 | }, 31 | test 32 | ); 33 | }; 34 | -------------------------------------------------------------------------------- /test/test-nodejs-predefines.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint tests for Node.js predefines working correctly 3 | * 4 | * Released into the Public Domain by tav 5 | * See the README.md for full credits of the awesome contributors! 6 | */ 7 | 8 | /** 9 | * Module dependencies 10 | */ 11 | var helper = require('./helper'); 12 | 13 | /** 14 | * Test for Node.js predefines working correctly 15 | * 16 | * @param test 17 | */ 18 | exports.NodePredefines = function (test) { 19 | helper.testConsoleOutput( 20 | './nodelint', 21 | [__dirname + '/fixtures/nodejs-predefines.js'], 22 | { 23 | stdout: '0 errors\n', 24 | stderr: '', 25 | exitCode: 0 26 | }, 27 | test 28 | ); 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /test/test-reporters-no-errors.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint reporters tests 3 | * 4 | * Released into the Public Domain by tav 5 | * See the README.md for full credits of the awesome contributors! 6 | */ 7 | 8 | /** 9 | * Module dependencies 10 | */ 11 | var helper = require('./helper'); 12 | 13 | /** 14 | * Test for default reporter 15 | * 16 | * @param test 17 | */ 18 | exports.Default = function (test) { 19 | helper.testConsoleOutput( 20 | './nodelint', 21 | ['--reporter=default', __dirname + '/fixtures/no-errors.js'], 22 | { 23 | stdout: '0 errors\n', 24 | stderr: '', 25 | exitCode: 0 26 | }, 27 | test 28 | ); 29 | }; 30 | 31 | /** 32 | * Test for IDEA reporter 33 | * 34 | * @param test 35 | */ 36 | exports.IDEA = function (test) { 37 | helper.testConsoleOutput( 38 | './nodelint', 39 | ['--reporter=idea', __dirname + '/fixtures/no-errors.js'], 40 | { 41 | stdout: '', 42 | stderr: '', 43 | exitCode: 0 44 | }, 45 | test 46 | ); 47 | }; 48 | 49 | /** 50 | * Test for Textmate full HTML reporter 51 | * 52 | * @param test 53 | */ 54 | exports.TextmateFull = function (test) { 55 | var expectedStdout = '

    0 Errors


      \n'; 64 | helper.testConsoleOutput( 65 | './nodelint', 66 | ['--reporter=textmate_full', __dirname + '/fixtures/no-errors.js'], 67 | { 68 | stdout: expectedStdout, 69 | stderr: '', 70 | exitCode: 0 71 | }, 72 | test 73 | ); 74 | }; 75 | 76 | /** 77 | * Test for Textmate summary reporter 78 | * 79 | * @param test 80 | */ 81 | exports.TextmateSummary = function (test) { 82 | helper.testConsoleOutput( 83 | './nodelint', 84 | ['--reporter=textmate_summary', __dirname + '/fixtures/no-errors.js'], 85 | { 86 | stdout: '', 87 | stderr: '', 88 | exitCode: 0 89 | }, 90 | test 91 | ); 92 | }; 93 | 94 | /** 95 | * Test for VIM reporter 96 | * 97 | * @param test 98 | */ 99 | exports.VIM = function (test) { 100 | helper.testConsoleOutput( 101 | './nodelint', 102 | ['--reporter=vim', __dirname + '/fixtures/no-errors.js'], 103 | { 104 | stdout: '', 105 | stderr: '', 106 | exitCode: 0 107 | }, 108 | test 109 | ); 110 | }; 111 | 112 | /** 113 | * Test for XML reporter 114 | * 115 | * @param test 116 | */ 117 | exports.XML = function (test) { 118 | helper.testConsoleOutput( 119 | './nodelint', 120 | ['--reporter=xml', __dirname + '/fixtures/no-errors.js'], 121 | { 122 | stdout: '\n\n\n', 123 | stderr: '', 124 | exitCode: 0 125 | }, 126 | test 127 | ); 128 | }; 129 | -------------------------------------------------------------------------------- /test/test-reporters-some-errors.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint tests for JS file with Lint errors 3 | * 4 | * Released into the Public Domain by tav 5 | * See the README.md for full credits of the awesome contributors! 6 | */ 7 | 8 | /** 9 | * Module dependencies 10 | */ 11 | var helper = require('./helper'); 12 | 13 | /** 14 | * Test for default reporter, no coloring 15 | * 16 | * @param test 17 | */ 18 | exports.DefaultNoColor = function (test) { 19 | var env = process.env; 20 | env.NODE_DISABLE_COLORS = 1; 21 | 22 | helper.testConsoleOutput( 23 | './nodelint', 24 | ['--reporter=default', __dirname + '/fixtures/some-errors.js.nolint'], 25 | {env: env}, 26 | { 27 | stdout: __dirname + "/fixtures/some-errors.js.nolint, line 5, character 7: " 28 | + "Expected a conditional expression and instead saw an assignment.\n" 29 | + "if (a = b) {\n1 error\n", 30 | stderr: '', 31 | exitCode: 2 32 | }, 33 | test 34 | ); 35 | }; 36 | 37 | /** 38 | * Test for default reporter, coloring 39 | * 40 | * @param test 41 | */ 42 | exports.DefaultColor = function (test) { 43 | var env = process.env; 44 | env.NODE_DISABLE_COLORS = 0; 45 | 46 | helper.testConsoleOutput( 47 | './nodelint', 48 | ['--reporter=default', __dirname + '/fixtures/some-errors.js.nolint'], 49 | {env: env}, 50 | { 51 | stdout: "\u001b[1;31m" 52 | + __dirname + "/fixtures/some-errors.js.nolint, line 5, character 7:\u001b[0m " 53 | + "Expected a conditional expression and instead saw an assignment.\n" 54 | + "if (a = b) {\n1 error\n", 55 | stderr: '', 56 | exitCode: 2 57 | }, 58 | test 59 | ); 60 | }; 61 | 62 | /** 63 | * Test for Textmate summary reporter 64 | * 65 | * @param test 66 | */ 67 | exports.TextmateSummary = function (test) { 68 | var env = process.env; 69 | env.NODE_DISABLE_COLORS = 1; 70 | 71 | helper.testConsoleOutput( 72 | './nodelint', 73 | ['--reporter=textmate_summary', __dirname + '/fixtures/some-errors.js.nolint'], 74 | {env: env}, 75 | { 76 | stdout: "some-errors.js.nolint: line 5, character 7, " 77 | + "Expected a conditional expression and instead saw an assignment.\n" 78 | + "if (a = b) {\n\n1 error\n", 79 | stderr: '', 80 | exitCode: 2 81 | }, 82 | test 83 | ); 84 | }; 85 | -------------------------------------------------------------------------------- /test/test-single-file.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Nodelint tests for single file linting 3 | * 4 | * Released into the Public Domain by tav 5 | * See the README.md for full credits of the awesome contributors! 6 | */ 7 | 8 | /** 9 | * Module dependencies 10 | */ 11 | var helper = require('./helper'); 12 | 13 | /** 14 | * Test for 2-space indent file 15 | * 16 | * @param test 17 | */ 18 | exports.Node2SpaceIndent = function (test) { 19 | helper.testConsoleOutput( 20 | './nodelint', 21 | [__dirname + '/fixtures/node-2-space-indent.js'], 22 | { 23 | stdout: '0 errors\n', 24 | stderr: '', 25 | exitCode: 0 26 | }, 27 | test 28 | ); 29 | }; 30 | 31 | /** 32 | * Test for s-space indent file 33 | * 34 | * @param test 35 | */ 36 | exports.Node4SpaceIndent = function (test) { 37 | helper.testConsoleOutput( 38 | './nodelint', 39 | [__dirname + '/fixtures/node-4-space-indent.js'], 40 | { 41 | stdout: '0 errors\n', 42 | stderr: '', 43 | exitCode: 0 44 | }, 45 | test 46 | ); 47 | }; 48 | 49 | 50 | /** 51 | * Test for 4-space indent file with browser js 52 | * 53 | * @param test 54 | */ 55 | exports.Browser4SpaceIndent = function (test) { 56 | helper.testConsoleOutput( 57 | './nodelint', 58 | [__dirname + '/fixtures/browser-4-space-indent.js'], 59 | { 60 | stdout: '0 errors\n', 61 | stderr: '', 62 | exitCode: 0 63 | }, 64 | test 65 | ); 66 | }; 67 | --------------------------------------------------------------------------------