Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Custom Reporter and Local Module

New reporter, specifically for Sublime! Outputs errors and warnings with clear hierarchy only only listing the file one time. Closes #15.

Local jshint npm module to simplify installation and better prevent user errors related to paths. Closes #16.
  • Loading branch information...
commit 0ba4fa7518b67d350d8af5fa7f1cebe4ea9131f2 1 parent 729ac68
Jamie Hoover ⚔ authored
Showing with 7,144 additions and 2 deletions.
  1. +25 −0 .jshintrc
  2. +5 −2 JSHint.sublime-build
  3. +1 −0  node_modules/.bin/jshint
  4. +3 −0  node_modules/jshint/.gitmodules
  5. +3 −0  node_modules/jshint/.jshintignore
  6. +40 −0 node_modules/jshint/.jshintrc
  7. +3 −0  node_modules/jshint/.npmignore
  8. +9 −0 node_modules/jshint/HELP
  9. +4 −0 node_modules/jshint/LICENSE
  10. +71 −0 node_modules/jshint/README.md
  11. +2 −0  node_modules/jshint/bin/hint
  12. +140 −0 node_modules/jshint/lib/cli.js
  13. +108 −0 node_modules/jshint/lib/hint.js
  14. +18 −0 node_modules/jshint/lib/reporters/default.js
  15. +54 −0 node_modules/jshint/lib/reporters/jslint_xml.js
  16. +45 −0 node_modules/jshint/lib/reporters/non_error.js
  17. +1 −0  node_modules/jshint/node_modules/argsparser/.npmignore
  18. +4 −0 node_modules/jshint/node_modules/argsparser/Makefile
  19. +1 −0  node_modules/jshint/node_modules/argsparser/index.js
  20. +41 −0 node_modules/jshint/node_modules/argsparser/lib/argsparser.js
  21. +40 −0 node_modules/jshint/node_modules/argsparser/package.json
  22. +34 −0 node_modules/jshint/node_modules/argsparser/readme.md
  23. +39 −0 node_modules/jshint/node_modules/argsparser/test/test.js
  24. +4 −0 node_modules/jshint/node_modules/minimatch/.travis.yml
  25. +23 −0 node_modules/jshint/node_modules/minimatch/LICENSE
  26. +212 −0 node_modules/jshint/node_modules/minimatch/README.md
  27. +980 −0 node_modules/jshint/node_modules/minimatch/minimatch.js
  28. +1 −0  node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/.npmignore
  29. +23 −0 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/LICENSE
  30. +12 −0 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/README.md
  31. +100 −0 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js
  32. +35 −0 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/package.json
  33. +93 −0 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/test/basic.js
  34. +40 −0 node_modules/jshint/node_modules/minimatch/package.json
  35. +261 −0 node_modules/jshint/node_modules/minimatch/test/basic.js
  36. +33 −0 node_modules/jshint/node_modules/minimatch/test/brace-expand.js
  37. +14 −0 node_modules/jshint/node_modules/minimatch/test/caching.js
  38. +48 −0 node_modules/jshint/package.json
  39. +1 −0  node_modules/jshint/packages/jshint/.npmignore
  40. +72 −0 node_modules/jshint/packages/jshint/README.markdown
  41. +4,390 −0 node_modules/jshint/packages/jshint/jshint.js
  42. +37 −0 package.json
  43. +74 −0 reporter.js
View
25 .jshintrc
@@ -0,0 +1,25 @@
+{
+ "predef": [],
+ "node": true,
+ "es5": true,
+ "bitwise": true,
+ "curly": true,
+ "eqeqeq": true,
+ "forin": true,
+ "immed": true,
+ "latedef": true,
+ "newcap": true,
+ "noarg": true,
+ "noempty": true,
+ "nonew": true,
+ "plusplus": true,
+ "regexp": false, // These are only build/test scripts. Security is not an issue.
+ "undef": true,
+ "strict": true,
+ "trailing": true,
+ "globalstrict": true,
+ "nonstandard": true,
+ "white": true,
+ "indent": 2,
+ "onevar": true
+}
View
7 JSHint.sublime-build
@@ -1,6 +1,9 @@
{
- "cmd": ["jshint", "$file"],
- "file_regex": "(.+js).+((?<=line\\s)\\d+).+((?<=col\\s)\\d+),\\s(.+$)",
+ "cmd": ["${packages}/JSHint/node_modules/.bin/jshint", "$file", "--reporter", "${packages}/JSHint/reporter.js"],
+
+ "file_regex": "file:\\s(.+)\\]",
+ "line_regex": "(\\d+),(\\d+)",
+
"selector": "source.js",
"osx": {
View
1  node_modules/.bin/jshint
View
3  node_modules/jshint/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "packages/jshint"]
+ path = packages/jshint
+ url = git://github.com/jshint/jshint.git
View
3  node_modules/jshint/.jshintignore
@@ -0,0 +1,3 @@
+node_modules
+packages
+.git
View
40 node_modules/jshint/.jshintrc
@@ -0,0 +1,40 @@
+{
+ "predef": [
+ "jasmine",
+ "spyOn",
+ "it",
+ "console",
+ "describe",
+ "expect",
+ "beforeEach",
+ "waits",
+ "waitsFor",
+ "runs"
+ ],
+
+ "node" : true,
+ "es5" : true,
+ "browser" : true,
+
+ "boss" : false,
+ "curly": false,
+ "debug": false,
+ "devel": false,
+ "eqeqeq": true,
+ "evil": true,
+ "forin": false,
+ "immed": true,
+ "laxbreak": false,
+ "newcap": true,
+ "noarg": true,
+ "noempty": false,
+ "nonew": false,
+ "nomen": false,
+ "onevar": true,
+ "plusplus": false,
+ "regexp": false,
+ "undef": true,
+ "sub": true,
+ "strict": false,
+ "white": true
+}
View
3  node_modules/jshint/.npmignore
@@ -0,0 +1,3 @@
+tags
+node_modules
+test/system/.files
View
9 node_modules/jshint/HELP
@@ -0,0 +1,9 @@
+Usage: jshint path path2 [options]
+
+Options:
+
+ --version display package version
+ --config custom config file
+ --reporter custom reporter
+ --jslint-reporter use a jslint compatible xml reporter
+ --show-non-errors show additional data generated by jshint
View
4 node_modules/jshint/LICENSE
@@ -0,0 +1,4 @@
+** Licensed Under **
+
+ The MIT License
+ http://www.opensource.org/licenses/mit-license.php
View
71 node_modules/jshint/README.md
@@ -0,0 +1,71 @@
+# node-jshint
+
+A command line interface and npm package for jshint.
+
+## Install
+
+To use jshint from any location (for npm v1.x) you need to install using the global (-g) flag.
+
+ npm install -g jshint
+
+## Usage
+
+The command line interface looks like this.
+
+ jshint path path2 [options]
+
+You can also require JSHint itself as a module.
+
+ var jshint = require('jshint');
+
+Note: If you are using npm v1.x be sure to install jshint locally (without the -g flag) or link it globally.
+
+## Text Editor Plugins
+
+* [gedit-node-jshint](https://github.com/niftylettuce/gedit-node-jshint) - Simply use CTRL+J in gedit to run JSHint using `node-jshint`.
+* [vim syntastic](https://github.com/scrooloose/syntastic) - Run node-jshint at each file save.
+* [sublime-jshint](https://github.com/uipoet/sublime-jshint) - `F7` or `command-B` on any .js file. `F4` next error line,column. `shift-F4` previous error line,column.
+
+## Custom Reporters
+
+Specify a custom reporter module (see example/reporter.js).
+
+ --reporter path/to/reporter.js
+
+Use a jslint compatible xml reporter.
+
+ --jslint-reporter
+
+Show additional non-error data generated by jshint (unused globals etc).
+
+ --show-non-errors
+
+## Custom Options
+
+Specify custom lint options (see [example/config.json](https://github.com/jshint/node-jshint/blob/master/example/config.json)).
+
+ --config path/to/config.json
+
+Note: This bypasses any .jshintrc files.
+
+## Default Options
+
+The CLI uses the default options that come with JSHint. However, if it locates a .jshintrc file in your home directory (~/) it will use those options first.
+
+## Per Directory Options
+
+If there is a .jshintrc file in the current working directory, any of those options will take precedence over (or be merged with) any options found in the ~/.jshintrc file (if it exists).
+
+## Ignoring Files and Directories
+
+If there is a .jshintignore file in the current working directory, then any directories or files will be skipped over.
+
+Note: Pattern matching uses minimatch, with the nocase [option](https://github.com/isaacs/minimatch). When there is no match, it performs a left side match (when no forward slashes present and path is a directory).
+
+## Installing dependencies for development
+
+ ./configure
+
+## Build Commands
+
+ jake -T
View
2  node_modules/jshint/bin/hint
@@ -0,0 +1,2 @@
+#!/usr/bin/env node
+require('./../lib/cli').interpret(process.argv);
View
140 node_modules/jshint/lib/cli.js
@@ -0,0 +1,140 @@
+var fs = require('fs'),
+ path = require('path'),
+ argsparser = require('argsparser'),
+ hint = require('./hint');
+
+function existsSync() {
+ var obj = fs.existsSync ? fs : path;
+ return obj.existsSync.apply(obj, arguments);
+}
+
+function _help() {
+ process.stdout.write(fs.readFileSync(__dirname + "/../HELP", "utf-8"));
+}
+
+function _version() {
+ process.stdout.write(JSON.parse(fs.readFileSync(__dirname + "/../package.json", "utf-8")).version + "\n");
+}
+
+function _removeJsComments(str) {
+ str = str || '';
+ str = str.replace(/\/\*[\s\S]*(?:\*\/)/g, ''); //everything between "/* */"
+ str = str.replace(/\/\/[^\n\r]*/g, ''); //everything after "//"
+ return str;
+}
+
+function _loadAndParseConfig(filePath) {
+ return existsSync(filePath) ?
+ JSON.parse(_removeJsComments(fs.readFileSync(filePath, "utf-8"))) : {};
+}
+
+function _mergeConfigs(homerc, cwdrc) {
+ var homeConfig = _loadAndParseConfig(homerc),
+ cwdConfig = _loadAndParseConfig(cwdrc),
+ prop;
+
+ for (prop in cwdConfig) {
+ if (typeof prop === 'string') {
+ if (prop === 'predef') {
+ homeConfig.predef = (homeConfig.predef || []).concat(cwdConfig.predef);
+ } else {
+ homeConfig[prop] = cwdConfig[prop];
+ }
+ }
+ }
+
+ return homeConfig;
+}
+
+function _print(results) {
+ function exit() {
+ process.exit(results.length > 0 ? 1 : 0);
+ }
+
+ // avoid stdout cutoff in node 0.4.x, also supports 0.5.x
+ // see https://github.com/joyent/node/issues/1669
+ try {
+ if (!process.stdout.flush()) {
+ process.stdout.once("drain", exit);
+ } else {
+ exit();
+ }
+ } catch (e) {
+ exit();
+ }
+}
+
+module.exports = {
+ interpret: function (args) {
+ var config, reporter, ignore,
+ options = argsparser.parse(args),
+ pathsToIgnore = path.join(process.cwd(), '.jshintignore'),
+ defaultConfig = path.join(process.env.HOME, '.jshintrc'),
+ projectConfig = path.join(process.cwd(), '.jshintrc'),
+ customConfig = options["--config"],
+ customReporter = options["--reporter"] ? path.resolve(process.cwd(), options["--reporter"]) : null,
+ targets = options.node;
+
+ //could be on Windows which we are looking for an attribute ending in 'node.exe'
+ if (targets === undefined) {
+ (function () {
+ var arg;
+
+ for (arg in options) {
+ if (path.basename(arg) === 'node.exe') {
+ targets = options[arg];
+ break;
+ }
+ }
+ }());
+ }
+
+ targets = typeof targets === "string" ? null : targets.slice(1);
+
+
+ if (options["--version"]) {
+ _version();
+ return;
+ }
+
+ if (!targets || options["--help"]) {
+ _help();
+ return;
+ }
+
+ if (options["--jslint-reporter"]) {
+ customReporter = "./reporters/jslint_xml.js";
+ }
+
+ if (options["--show-non-errors"]) {
+ customReporter = "./reporters/non_error.js";
+ }
+
+ if (customConfig) {
+ config = _loadAndParseConfig(customConfig);
+ } else {
+ config = _mergeConfigs(defaultConfig, projectConfig);
+ }
+
+ if (customReporter) {
+ try {
+ reporter = require(customReporter).reporter;
+ } catch (r) {
+ process.stdout.write("Error opening reporter file: " + customReporter);
+ process.stdout.write(r + "\n");
+ process.exit(1);
+ }
+ }
+
+ if (existsSync(pathsToIgnore)) {
+ ignore = fs.readFileSync(pathsToIgnore, "utf-8").split("\n").map(function (line) {
+ return line.trim();
+ }).filter(function (line) {
+ return !!line;
+ });
+ }
+
+ _print(hint.hint(targets, config, reporter, ignore));
+ }
+};
+
View
108 node_modules/jshint/lib/hint.js
@@ -0,0 +1,108 @@
+var fs = require('fs'),
+ minimatch = require('minimatch'),
+ path = require('path'),
+ jshint = require('./../packages/jshint/jshint.js'),
+ _reporter = require('./reporters/default').reporter,
+ _cache = {
+ directories: {}
+ };
+
+function _lint(file, results, config, data) {
+ var buffer,
+ lintdata;
+
+ try {
+ buffer = fs.readFileSync(file, 'utf-8');
+ } catch (e) {
+ process.stdout.write("Error: Cant open: " + file);
+ process.stdout.write(e + '\n');
+ }
+
+ // Remove potential Unicode Byte Order Mark.
+ buffer = buffer.replace(/^\uFEFF/, '');
+
+ if (!jshint.JSHINT(buffer, config)) {
+ jshint.JSHINT.errors.forEach(function (error) {
+ if (error) {
+ results.push({file: file, error: error});
+ }
+ });
+ }
+
+ lintdata = jshint.JSHINT.data();
+
+ if (lintdata) {
+ lintdata.file = file;
+ data.push(lintdata);
+ }
+}
+
+function isDirectory(aPath) {
+ var isDir;
+
+ try {
+ if (_cache.directories.hasOwnProperty(aPath)) {
+ isDir = _cache.directories[aPath];
+ } else {
+ isDir = fs.statSync(aPath).isDirectory();
+ _cache.directories[aPath] = isDir;
+ }
+ } catch (e) {
+ isDir = false;
+ }
+
+ return isDir;
+}
+
+
+function _shouldIgnore(somePath, ignore) {
+ function isIgnored(p) {
+ var fnmatch = minimatch(somePath, p, {nocase: true}),
+ lsmatch = isDirectory(p) && p.match(/^[^\/]*\/?$/) &&
+ somePath.match(new RegExp("^" + p + ".*"));
+
+ return !!(fnmatch || lsmatch);
+ }
+
+ return ignore.some(function (ignorePath) {
+ return isIgnored(ignorePath);
+ });
+}
+
+function _collect(filePath, files, ignore) {
+ if (ignore && _shouldIgnore(filePath, ignore)) {
+ return;
+ }
+
+ if (fs.statSync(filePath).isDirectory()) {
+ fs.readdirSync(filePath).forEach(function (item) {
+ _collect(path.join(filePath, item), files, ignore);
+ });
+ } else if (filePath.match(/\.js$/)) {
+ files.push(filePath);
+ }
+}
+
+module.exports = {
+ hint: function (targets, config, reporter, ignore) {
+ var files = [],
+ results = [],
+ data = [];
+
+ targets.forEach(function (target) {
+ _collect(target, files, ignore);
+ });
+
+ files.forEach(function (file) {
+ _lint(file, results, config, data);
+ });
+
+ _cache = {
+ directories: {}
+ };
+
+ (reporter || _reporter)(results, data);
+
+ return results;
+ }
+};
View
18 node_modules/jshint/lib/reporters/default.js
@@ -0,0 +1,18 @@
+module.exports = {
+ reporter: function (results, data) {
+ var len = results.length,
+ str = '',
+ file, error;
+
+ results.forEach(function (result) {
+ file = result.file;
+ error = result.error;
+ str += file + ': line ' + error.line + ', col ' +
+ error.character + ', ' + error.reason + '\n';
+ });
+
+ if (str) {
+ process.stdout.write(str + "\n" + len + ' error' + ((len === 1) ? '' : 's') + "\n");
+ }
+ }
+};
View
54 node_modules/jshint/lib/reporters/jslint_xml.js
@@ -0,0 +1,54 @@
+// Author: Vasili Sviridov
+// http://github.com/vsviridov
+module.exports =
+{
+ reporter: function (results)
+ {
+ "use strict";
+
+ var files = {},
+ out = [],
+ pairs = {
+ "&": "&amp;",
+ '"': "&quot;",
+ "'": "&apos;",
+ "<": "&lt;",
+ ">": "&gt;"
+ },
+ file, i, issue;
+
+ function encode(s) {
+ for (var r in pairs) {
+ if (typeof(s) !== "undefined") {
+ s = s.replace(new RegExp(r, "g"), pairs[r]);
+ }
+ }
+ return s || "";
+ }
+
+
+ results.forEach(function (result) {
+ result.file = result.file.replace(/^\.\//, '');
+ if (!files[result.file]) {
+ files[result.file] = [];
+ }
+ files[result.file].push(result.error);
+ });
+
+ out.push("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
+ out.push("<jslint>");
+
+ for (file in files) {
+ out.push("\t<file name=\"" + file + "\">");
+ for (i = 0; i < files[file].length; i++) {
+ issue = files[file][i];
+ out.push("\t\t<issue line=\"" + issue.line + "\" char=\"" + issue.character + "\" reason=\"" + encode(issue.reason) + "\" evidence=\"" + encode(issue.evidence) + "\" />");
+ }
+ out.push("\t</file>");
+ }
+
+ out.push("</jslint>");
+
+ process.stdout.write(out.join("\n") + "\n");
+ }
+};
View
45 node_modules/jshint/lib/reporters/non_error.js
@@ -0,0 +1,45 @@
+/*jshint node: true */
+module.exports =
+{
+ reporter: function (results, data, done) {
+ var len = results.length,
+ str = '',
+ file, error, globals, unuseds;
+
+ results.forEach(function (result) {
+ file = result.file;
+ error = result.error;
+ str += file + ': line ' + error.line + ', col ' +
+ error.character + ', ' + error.reason + '\n';
+ });
+
+ str += len > 0 ? ("\n" + len + ' error' + ((len === 1) ? '' : 's')) : "";
+
+ data.forEach(function (data) {
+ file = data.file;
+ globals = data.implieds;
+ unuseds = data.unused;
+
+ if (globals || unuseds) {
+ str += '\n\n' + file + ' :\n';
+ }
+
+ if (globals) {
+ str += '\tImplied globals:\n';
+ globals.forEach(function (global) {
+ str += '\t\t' + global.name + ': ' + global.line + '\n';
+ });
+ }
+ if (unuseds) {
+ str += '\tUnused Variables:\n\t\t';
+ unuseds.forEach(function (unused) {
+ str += unused.name + '(' + unused.line + '), ';
+ });
+ }
+ });
+
+ if (str) {
+ process.stdout.write(str + "\n");
+ }
+ }
+};
View
1  node_modules/jshint/node_modules/argsparser/.npmignore
@@ -0,0 +1 @@
+.DS_Store
View
4 node_modules/jshint/node_modules/argsparser/Makefile
@@ -0,0 +1,4 @@
+test:
+ node test/test.js
+
+.PHONY: test
View
1  node_modules/jshint/node_modules/argsparser/index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/argsparser');
View
41 node_modules/jshint/node_modules/argsparser/lib/argsparser.js
@@ -0,0 +1,41 @@
+/**
+ * Parser arguments array
+ * @param {Array} args optional arguments arrray.
+ * @return {Object} opts key value hash.
+ * @export
+ */
+exports.parse = function(args) {
+ // args is optional, default is process.argv
+ args = args || process.argv;
+
+ var opts = {}, curSwitch;
+
+ args.forEach(function(arg) {
+ // its a switch
+ if (/^(-|--)/.test(arg) || !curSwitch) {
+ opts[arg] = true;
+ curSwitch = arg;
+ // this arg is a data
+ } else {
+ if (arg === 'false') {
+ arg = false;
+ } else if (arg === 'true') {
+ arg = true;
+ } else if (!isNaN(arg)) {
+ arg = Number(arg);
+ }
+
+ // it was a boolean switch per default,
+ // now it has got a val
+ if (typeof opts[curSwitch] === 'boolean') {
+ opts[curSwitch] = arg;
+ } else if (Array.isArray(opts[curSwitch])) {
+ opts[curSwitch].push(arg);
+ } else {
+ opts[curSwitch] = [opts[curSwitch], arg];
+ }
+ }
+ });
+
+ return opts;
+};
View
40 node_modules/jshint/node_modules/argsparser/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "argsparser",
+ "description": "A tiny command line arguments parser",
+ "version": "0.0.6",
+ "author": {
+ "name": "Oleg Slobodskoi",
+ "email": "oleg008@gmail.com"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/kof/node-argsparser.git"
+ },
+ "keywords": [
+ "arguments",
+ "options",
+ "command line",
+ "parser"
+ ],
+ "engines": {
+ "node": ">= 0.2.0"
+ },
+ "scripts": {
+ "test": "node ./test/test.js"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "http://www.opensource.org/licenses/mit-license.php"
+ }
+ ],
+ "_id": "argsparser@0.0.6",
+ "dependencies": {},
+ "devDependencies": {},
+ "optionalDependencies": {},
+ "_engineSupported": true,
+ "_npmVersion": "1.1.4",
+ "_nodeVersion": "v0.6.12",
+ "_defaultsLoaded": true,
+ "_from": "argsparser@>=0.0.3"
+}
View
34 node_modules/jshint/node_modules/argsparser/readme.md
@@ -0,0 +1,34 @@
+## Yet another tiny arguments parser for node
+
+## Features
+ * extremely tiny
+ * instead to parse all possible spellings, it uses just some simple rules
+
+## How this parser works
+The target is to get a key-value object from an array. A key can be the first element or element prefixed by "-" and "--" (switch).
+So the parser loops through the array and looks for keys. After he could detect an a key all next elements will be added as a value of this key until he find another key.
+If there is no value, then the key is true (boolean). If there are a lot of values, then the key is an array.
+
+## Examples
+
+node script.js -> {"node": "script.js"}
+
+node script.js -o -> {"node": "script.js", "-o": true}
+
+node script.js -o test -> {"node": "script.js", "-o": "test"}
+
+node script.js -a testa --b testb -> {node: "script.js", "-a": "testa", "--b": "testb"}
+
+node script.js -paths /test.js /test1.js -> {node: "script.js", "-paths": ["/test.js", "/test1.js"]}
+
+## Usage
+
+ // per default it parses process.argv
+ var args = require( "argsparser" ).parse(); // {"node": "/path/to/your/script.js"}
+
+ // optional you can pass your own arguments array
+ var args = require( "argsparser" ).parse(["-a", "test"]); // {"-a": "test"}
+
+
+## Installation
+ npm install argsparser
View
39 node_modules/jshint/node_modules/argsparser/test/test.js
@@ -0,0 +1,39 @@
+var a = require('assert'),
+ util = require('util'),
+ parse = require('../lib/argsparser').parse;
+
+util.print('Run tests...\n');
+
+a.deepEqual(parse(), {node: __filename}, 'node script.js');
+
+a.deepEqual(parse(['-o']), {'-o': true}, 'node script.js -o');
+
+a.deepEqual(parse(['-o', 'true']), {'-o': true}, 'node script.js -o true');
+
+a.deepEqual(parse(['-o', 'false']), {'-o': false}, 'node script.js -o false');
+
+a.deepEqual(parse(['-o', '123']), {'-o': 123}, 'node script.js -o 123');
+
+a.deepEqual(parse(['--token', 'bla--bla']), {'--token': 'bla--bla'}, 'node script.js --token bla--bla');
+
+a.deepEqual(parse(['-o', '123.456']), {'-o': 123.456}, 'node script.js -o 123.456');
+
+a.deepEqual(parse(['-o', 'test']), {'-o': 'test'}, 'node script.js -o test');
+
+a.deepEqual(parse(['-a', 'testa', '-b', 'testb']), {'-a': 'testa', '-b': 'testb'}, 'node script.js -a testa -b testb');
+
+a.deepEqual(parse(['--a', 'testa', '--b', 'testb']), {'--a': 'testa', '--b': 'testb'}, 'node script.js --a testa --b testb ');
+
+a.deepEqual(parse(['-a', 'testa', '--b', 'testb']), {'-a': 'testa', '--b': 'testb'}, 'node script.js -a testa --b testb');
+
+a.deepEqual(parse(['--a', 'testa', '-b', 'testb']), {'--a': 'testa', '-b': 'testb'}, 'node script.js --a testa -b testb');
+
+a.deepEqual(parse(['-paths', '/test.js', '/test1.js']), {'-paths': ['/test.js', '/test1.js']}, 'node script.js -paths /test.js /test1.js');
+
+a.deepEqual(parse(['--paths', '/test.js', '/test1.js']), {'--paths': ['/test.js', '/test1.js']}, 'node script.js --paths /test.js /test1.js');
+
+a.deepEqual(parse(['--paths', '/test.js', '/test1.js', '-a', 'testa']), {'--paths': ['/test.js', '/test1.js'], '-a': 'testa'}, 'node script.js --paths /test.js /test1.js -a testa');
+
+a.deepEqual(parse(['--port', '80', '8080']), {'--port': [80, 8080]}, 'node server.js --port 80 8080');
+
+util.print('All tests ok\n');
View
4 node_modules/jshint/node_modules/minimatch/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.4
+ - 0.6
View
23 node_modules/jshint/node_modules/minimatch/LICENSE
@@ -0,0 +1,23 @@
+Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
View
212 node_modules/jshint/node_modules/minimatch/README.md
@@ -0,0 +1,212 @@
+# minimatch
+
+A minimal matching utility.
+
+[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.png)](http://travis-ci.org/isaacs/minimatch)
+
+
+This is the matching library used internally by npm.
+
+Eventually, it will replace the C binding in node-glob.
+
+It works by converting glob expressions into JavaScript `RegExp`
+objects.
+
+## Usage
+
+```javascript
+var minimatch = require("minimatch")
+
+minimatch("bar.foo", "*.foo") // true!
+minimatch("bar.foo", "*.bar") // false!
+```
+
+## Features
+
+Supports these glob features:
+
+* Brace Expansion
+* Extended glob matching
+* "Globstar" `**` matching
+
+See:
+
+* `man sh`
+* `man bash`
+* `man 3 fnmatch`
+* `man 5 gitignore`
+
+### Comparisons to other fnmatch/glob implementations
+
+While strict compliance with the existing standards is a worthwhile
+goal, some discrepancies exist between minimatch and other
+implementations, and are intentional.
+
+If the pattern starts with a `!` character, then it is negated. Set the
+`nonegate` flag to suppress this behavior, and treat leading `!`
+characters normally. This is perhaps relevant if you wish to start the
+pattern with a negative extglob pattern like `!(a|B)`. Multiple `!`
+characters at the start of a pattern will negate the pattern multiple
+times.
+
+If a pattern starts with `#`, then it is treated as a comment, and
+will not match anything. Use `\#` to match a literal `#` at the
+start of a line, or set the `nocomment` flag to suppress this behavior.
+
+The double-star character `**` is supported by default, unless the
+`noglobstar` flag is set. This is supported in the manner of bsdglob
+and bash 4.1, where `**` only has special significance if it is the only
+thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but
+`a/**b` will not. **Note that this is different from the way that `**` is
+handled by ruby's `Dir` class.**
+
+If an escaped pattern has no matches, and the `null` flag is not set,
+then minimatch.match returns the pattern as-provided, rather than
+interpreting the character escapes. For example,
+`minimatch.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than
+`"*a?"`.
+
+If brace expansion is not disabled, then it is performed before any
+other interpretation of the glob pattern. Thus, a pattern like
+`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded
+**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are
+checked for validity. Since those two are valid, matching proceeds.
+
+
+## Minimatch Class
+
+Create a minimatch object by instanting the `minimatch.Minimatch` class.
+
+```javascript
+var Minimatch = require("minimatch").Minimatch
+var mm = new Minimatch(pattern, options)
+```
+
+### Properties
+
+* `pattern` The original pattern the minimatch object represents.
+* `options` The options supplied to the constructor.
+* `set` A 2-dimensional array of regexp or string expressions.
+ Each row in the
+ array corresponds to a brace-expanded pattern. Each item in the row
+ corresponds to a single path-part. For example, the pattern
+ `{a,b/c}/d` would expand to a set of patterns like:
+
+ [ [ a, d ]
+ , [ b, c, d ] ]
+
+ If a portion of the pattern doesn't have any "magic" in it
+ (that is, it's something like `"foo"` rather than `fo*o?`), then it
+ will be left as a string rather than converted to a regular
+ expression.
+
+* `regexp` Created by the `makeRe` method. A single regular expression
+ expressing the entire pattern. This is useful in cases where you wish
+ to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled.
+* `negate` True if the pattern is negated.
+* `comment` True if the pattern is a comment.
+* `empty` True if the pattern is `""`.
+
+### Methods
+
+* `makeRe` Generate the `regexp` member if necessary, and return it.
+ Will return `false` if the pattern is invalid.
+* `match(fname)` Return true if the filename matches the pattern, or
+ false otherwise.
+* `matchOne(fileArray, patternArray, partial)` Take a `/`-split
+ filename, and match it against a single row in the `regExpSet`. This
+ method is mainly for internal use, but is exposed so that it can be
+ used by a glob-walker that needs to avoid excessive filesystem calls.
+
+All other methods are internal, and will be called as necessary.
+
+## Functions
+
+The top-level exported function has a `cache` property, which is an LRU
+cache set to store 100 items. So, calling these methods repeatedly
+with the same pattern and options will use the same Minimatch object,
+saving the cost of parsing it multiple times.
+
+### minimatch(path, pattern, options)
+
+Main export. Tests a path against the pattern using the options.
+
+```javascript
+var isJS = minimatch(file, "*.js", { matchBase: true })
+```
+
+### minimatch.filter(pattern, options)
+
+Returns a function that tests its
+supplied argument, suitable for use with `Array.filter`. Example:
+
+```javascript
+var javascripts = fileList.filter(minimatch.filter("*.js", {matchBase: true}))
+```
+
+### minimatch.match(list, pattern, options)
+
+Match against the list of
+files, in the style of fnmatch or glob. If nothing is matched, then
+return the pattern (unless `{ null: true }` in the options.)
+
+```javascript
+var javascripts = minimatch.match(fileList, "*.js", {matchBase: true}))
+```
+
+### minimatch.makeRe(pattern, options)
+
+Make a regular expression object from the pattern.
+
+## Options
+
+All options are `false` by default.
+
+### debug
+
+Dump a ton of stuff to stderr.
+
+### nobrace
+
+Do not expand `{a,b}` and `{1..3}` brace sets.
+
+### noglobstar
+
+Disable `**` matching against multiple folder names.
+
+### dot
+
+Allow patterns to match filenames starting with a period, even if
+the pattern does not explicitly have a period in that spot.
+
+Note that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot`
+is set.
+
+### noext
+
+Disable "extglob" style patterns like `+(a|b)`.
+
+### nocase
+
+Perform a case-insensitive match.
+
+### nonull
+
+When a match is not found by `minimatch.match`, return a list containing
+the pattern itself. When set, an empty list is returned if there are
+no matches.
+
+### matchBase
+
+If set, then patterns without slashes will be matched
+against the basename of the path if it contains slashes. For example,
+`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.
+
+### nocomment
+
+Suppress the behavior of treating `#` at the start of a pattern as a
+comment.
+
+### nonegate
+
+Suppress the behavior of treating a leading `!` character as negation.
View
980 node_modules/jshint/node_modules/minimatch/minimatch.js
@@ -0,0 +1,980 @@
+module.exports = minimatch
+minimatch.Minimatch = Minimatch
+
+var LRU = require("lru-cache")
+ , cache = minimatch.cache = new LRU(100)
+ , GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
+ , pathSplit = process.platform === "win32" ? /\\|\// : "/"
+
+var path = require("path")
+ // any single thing other than /
+ // don't need to escape / when using new RegExp()
+ , qmark = "[^/]"
+
+ // * => any number of characters
+ , star = qmark + "*?"
+
+ // ** when dots are allowed. Anything goes, except .. and .
+ // not (^ or / followed by one or two dots followed by $ or /),
+ // followed by anything, any number of times.
+ , twoStarDot = "(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?"
+
+ // not a ^ or / followed by a dot,
+ // followed by anything, any number of times.
+ , twoStarNoDot = "(?:(?!(?:\\\/|^)\\.).)*?"
+
+ // characters that need to be escaped in RegExp.
+ , reSpecials = charSet("().*{}+?[]^$\\!")
+
+// "abc" -> { a:true, b:true, c:true }
+function charSet (s) {
+ return s.split("").reduce(function (set, c) {
+ set[c] = true
+ return set
+ }, {})
+}
+
+// normalizes slashes.
+var slashSplit = /\/+/
+
+minimatch.monkeyPatch = monkeyPatch
+function monkeyPatch () {
+ var desc = Object.getOwnPropertyDescriptor(String.prototype, "match")
+ var orig = desc.value
+ desc.value = function (p) {
+ if (p instanceof Minimatch) return p.match(this)
+ return orig.call(this, p)
+ }
+ Object.defineProperty(String.prototype, desc)
+}
+
+minimatch.filter = filter
+function filter (pattern, options) {
+ options = options || {}
+ return function (p, i, list) {
+ return minimatch(p, pattern, options)
+ }
+}
+
+function minimatch (p, pattern, options) {
+ if (typeof pattern !== "string") {
+ throw new TypeError("glob pattern string required")
+ }
+
+ if (!options) options = {}
+
+ // shortcut: comments match nothing.
+ if (!options.nocomment && pattern.charAt(0) === "#") {
+ return false
+ }
+
+ // "" only matches ""
+ if (pattern.trim() === "") return p === ""
+
+ return new Minimatch(pattern, options).match(p)
+}
+
+function Minimatch (pattern, options) {
+ if (!(this instanceof Minimatch)) {
+ return new Minimatch(pattern, options, cache)
+ }
+
+ if (typeof pattern !== "string") {
+ throw new TypeError("glob pattern string required")
+ }
+
+ if (!options) options = {}
+ pattern = pattern.trim()
+
+ // lru storage.
+ // these things aren't particularly big, but walking down the string
+ // and turning it into a regexp can get pretty costly.
+ var cacheKey = pattern + "\n" + Object.keys(options).filter(function (k) {
+ return options[k]
+ }).join(":")
+ var cached = minimatch.cache.get(cacheKey)
+ if (cached) return cached
+ minimatch.cache.set(cacheKey, this)
+
+ this.options = options
+ this.set = []
+ this.pattern = pattern
+ this.regexp = null
+ this.negate = false
+ this.comment = false
+ this.empty = false
+
+ // make the set of regexps etc.
+ this.make()
+}
+
+Minimatch.prototype.make = make
+function make () {
+ // don't do it more than once.
+ if (this._made) return
+
+ var pattern = this.pattern
+ var options = this.options
+
+ // empty patterns and comments match nothing.
+ if (!options.nocomment && pattern.charAt(0) === "#") {
+ this.comment = true
+ return
+ }
+ if (!pattern) {
+ this.empty = true
+ return
+ }
+
+ // step 1: figure out negation, etc.
+ this.parseNegate()
+
+ // step 2: expand braces
+ var set = this.globSet = this.braceExpand()
+
+ if (options.debug) console.error(this.pattern, set)
+
+ // step 3: now we have a set, so turn each one into a series of path-portion
+ // matching patterns.
+ // These will be regexps, except in the case of "**", which is
+ // set to the GLOBSTAR object for globstar behavior,
+ // and will not contain any / characters
+ set = this.globParts = set.map(function (s) {
+ return s.split(slashSplit)
+ })
+
+ if (options.debug) console.error(this.pattern, set)
+
+ // glob --> regexps
+ set = set.map(function (s, si, set) {
+ return s.map(this.parse, this)
+ }, this)
+
+ if (options.debug) console.error(this.pattern, set)
+
+ // filter out everything that didn't compile properly.
+ set = set.filter(function (s) {
+ return -1 === s.indexOf(false)
+ })
+
+ if (options.debug) console.error(this.pattern, set)
+
+ this.set = set
+}
+
+Minimatch.prototype.parseNegate = parseNegate
+function parseNegate () {
+ var pattern = this.pattern
+ , negate = false
+ , options = this.options
+ , negateOffset = 0
+
+ if (options.nonegate) return
+
+ for ( var i = 0, l = pattern.length
+ ; i < l && pattern.charAt(i) === "!"
+ ; i ++) {
+ negate = !negate
+ negateOffset ++
+ }
+
+ if (negateOffset) this.pattern = pattern.substr(negateOffset)
+ this.negate = negate
+}
+
+// Brace expansion:
+// a{b,c}d -> abd acd
+// a{b,}c -> abc ac
+// a{0..3}d -> a0d a1d a2d a3d
+// a{b,c{d,e}f}g -> abg acdfg acefg
+// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
+//
+// Invalid sets are not expanded.
+// a{2..}b -> a{2..}b
+// a{b}c -> a{b}c
+minimatch.braceExpand = function (pattern, options) {
+ return new Minimatch(pattern, options).braceExpand()
+}
+
+Minimatch.prototype.braceExpand = braceExpand
+function braceExpand (pattern, options) {
+ options = options || this.options
+ pattern = typeof pattern === "undefined"
+ ? this.pattern : pattern
+
+ if (typeof pattern === "undefined") {
+ throw new Error("undefined pattern")
+ }
+
+ if (options.nobrace ||
+ !pattern.match(/\{.*\}/)) {
+ // shortcut. no need to expand.
+ return [pattern]
+ }
+
+ var escaping = false
+
+ // examples and comments refer to this crazy pattern:
+ // a{b,c{d,e},{f,g}h}x{y,z}
+ // expected:
+ // abxy
+ // abxz
+ // acdxy
+ // acdxz
+ // acexy
+ // acexz
+ // afhxy
+ // afhxz
+ // aghxy
+ // aghxz
+
+ // everything before the first \{ is just a prefix.
+ // So, we pluck that off, and work with the rest,
+ // and then prepend it to everything we find.
+ if (pattern.charAt(0) !== "{") {
+ // console.error(pattern)
+ var prefix = null
+ for (var i = 0, l = pattern.length; i < l; i ++) {
+ var c = pattern.charAt(i)
+ // console.error(i, c)
+ if (c === "\\") {
+ escaping = !escaping
+ } else if (c === "{" && !escaping) {
+ prefix = pattern.substr(0, i)
+ break
+ }
+ }
+
+ // actually no sets, all { were escaped.
+ if (prefix === null) {
+ // console.error("no sets")
+ return [pattern]
+ }
+
+ var tail = braceExpand(pattern.substr(i), options)
+ return tail.map(function (t) {
+ return prefix + t
+ })
+ }
+
+ // now we have something like:
+ // {b,c{d,e},{f,g}h}x{y,z}
+ // walk through the set, expanding each part, until
+ // the set ends. then, we'll expand the suffix.
+ // If the set only has a single member, then'll put the {} back
+
+ // first, handle numeric sets, since they're easier
+ var numset = pattern.match(/^\{(-?[0-9]+)\.\.(-?[0-9]+)\}/)
+ if (numset) {
+ // console.error("numset", numset[1], numset[2])
+ var suf = braceExpand(pattern.substr(numset[0].length), options)
+ , start = +numset[1]
+ , end = +numset[2]
+ , inc = start > end ? -1 : 1
+ , set = []
+ for (var i = start; i != (end + inc); i += inc) {
+ // append all the suffixes
+ for (var ii = 0, ll = suf.length; ii < ll; ii ++) {
+ set.push(i + suf[ii])
+ }
+ }
+ return set
+ }
+
+ // ok, walk through the set
+ // We hope, somewhat optimistically, that there
+ // will be a } at the end.
+ // If the closing brace isn't found, then the pattern is
+ // interpreted as braceExpand("\\" + pattern) so that
+ // the leading \{ will be interpreted literally.
+ var i = 1 // skip the \{
+ , depth = 1
+ , set = []
+ , member = ""
+ , sawEnd = false
+ , escaping = false
+
+ function addMember () {
+ set.push(member)
+ member = ""
+ }
+
+ // console.error("Entering for")
+ FOR: for (i = 1, l = pattern.length; i < l; i ++) {
+ var c = pattern.charAt(i)
+ // console.error("", i, c)
+
+ if (escaping) {
+ escaping = false
+ member += "\\" + c
+ } else {
+ switch (c) {
+ case "\\":
+ escaping = true
+ continue
+
+ case "{":
+ depth ++
+ member += "{"
+ continue
+
+ case "}":
+ depth --
+ // if this closes the actual set, then we're done
+ if (depth === 0) {
+ addMember()
+ // pluck off the close-brace
+ i ++
+ break FOR
+ } else {
+ member += c
+ continue
+ }
+
+ case ",":
+ if (depth === 1) {
+ addMember()
+ } else {
+ member += c
+ }
+ continue
+
+ default:
+ member += c
+ continue
+ } // switch
+ } // else
+ } // for
+
+ // now we've either finished the set, and the suffix is
+ // pattern.substr(i), or we have *not* closed the set,
+ // and need to escape the leading brace
+ if (depth !== 0) {
+ // console.error("didn't close", pattern)
+ return braceExpand("\\" + pattern, options)
+ }
+
+ // x{y,z} -> ["xy", "xz"]
+ // console.error("set", set)
+ // console.error("suffix", pattern.substr(i))
+ var suf = braceExpand(pattern.substr(i), options)
+ // ["b", "c{d,e}","{f,g}h"] ->
+ // [["b"], ["cd", "ce"], ["fh", "gh"]]
+ var addBraces = set.length === 1
+ // console.error("set pre-expanded", set)
+ set = set.map(function (p) {
+ return braceExpand(p, options)
+ })
+ // console.error("set expanded", set)
+
+
+ // [["b"], ["cd", "ce"], ["fh", "gh"]] ->
+ // ["b", "cd", "ce", "fh", "gh"]
+ set = set.reduce(function (l, r) {
+ return l.concat(r)
+ })
+
+ if (addBraces) {
+ set = set.map(function (s) {
+ return "{" + s + "}"
+ })
+ }
+
+ // now attach the suffixes.
+ var ret = []
+ for (var i = 0, l = set.length; i < l; i ++) {
+ for (var ii = 0, ll = suf.length; ii < ll; ii ++) {
+ ret.push(set[i] + suf[ii])
+ }
+ }
+ return ret
+}
+
+// parse a component of the expanded set.
+// At this point, no pattern may contain "/" in it
+// so we're going to return a 2d array, where each entry is the full
+// pattern, split on '/', and then turned into a regular expression.
+// A regexp is made at the end which joins each array with an
+// escaped /, and another full one which joins each regexp with |.
+//
+// Following the lead of Bash 4.1, note that "**" only has special meaning
+// when it is the *only* thing in a path portion. Otherwise, any series
+// of * is equivalent to a single *. Globstar behavior is enabled by
+// default, and can be disabled by setting options.noglobstar.
+Minimatch.prototype.parse = parse
+var SUBPARSE = {}
+function parse (pattern, isSub) {
+ var options = this.options
+
+ // shortcuts
+ if (!options.noglobstar && pattern === "**") return GLOBSTAR
+ if (pattern === "") return ""
+
+ var re = ""
+ , hasMagic = false
+ , escaping = false
+ // ? => one single character
+ , patternListStack = []
+ , plType
+ , stateChar
+ , inClass = false
+ , reClassStart = -1
+ , classStart = -1
+ // . and .. never match anything that doesn't start with .,
+ // even when options.dot is set.
+ , patternStart = pattern.charAt(0) === "." ? "" // anything
+ // not (start or / followed by . or .. followed by / or end)
+ : options.dot ? "(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))"
+ : "(?!\\.)"
+
+ function clearStateChar () {
+ if (stateChar) {
+ // we had some state-tracking character
+ // that wasn't consumed by this pass.
+ switch (stateChar) {
+ case "*":
+ re += star
+ hasMagic = true
+ break
+ case "?":
+ re += qmark
+ hasMagic = true
+ break
+ default:
+ re += "\\"+stateChar
+ break
+ }
+ stateChar = false
+ }
+ }
+
+ for ( var i = 0, len = pattern.length, c
+ ; (i < len) && (c = pattern.charAt(i))
+ ; i ++ ) {
+
+ if (options.debug) {
+ console.error("%s\t%s %s %j", pattern, i, re, c)
+ }
+
+ // skip over any that are escaped.
+ if (escaping && reSpecials[c]) {
+ re += "\\" + c
+ escaping = false
+ continue
+ }
+
+ SWITCH: switch (c) {
+ case "/":
+ // completely not allowed, even escaped.
+ // Should already be path-split by now.
+ return false
+
+ case "\\":
+ clearStateChar()
+ escaping = true
+ continue
+
+ // the various stateChar values
+ // for the "extglob" stuff.
+ case "?":
+ case "*":
+ case "+":
+ case "@":
+ case "!":
+ if (options.debug) {
+ console.error("%s\t%s %s %j <-- stateChar", pattern, i, re, c)
+ }
+
+ // all of those are literals inside a class, except that
+ // the glob [!a] means [^a] in regexp
+ if (inClass) {
+ if (c === "!" && i === classStart + 1) c = "^"
+ re += c
+ continue
+ }
+
+ // if we already have a stateChar, then it means
+ // that there was something like ** or +? in there.
+ // Handle the stateChar, then proceed with this one.
+ clearStateChar()
+ stateChar = c
+ // if extglob is disabled, then +(asdf|foo) isn't a thing.
+ // just clear the statechar *now*, rather than even diving into
+ // the patternList stuff.
+ if (options.noext) clearStateChar()
+ continue
+
+ case "(":
+ if (inClass) {
+ re += "("
+ continue
+ }
+
+ if (!stateChar) {
+ re += "\\("
+ continue
+ }
+
+ plType = stateChar
+ patternListStack.push({ type: plType
+ , start: i - 1
+ , reStart: re.length })
+ re += stateChar === "!" ? "(?!" : "(?:"
+ stateChar = false
+ continue
+
+ case ")":
+ if (inClass || !patternListStack.length) {
+ re += "\\)"
+ continue
+ }
+
+ hasMagic = true
+ re += ")"
+ plType = patternListStack.pop().type
+ switch (plType) {
+ case "?":
+ case "+":
+ case "*": re += plType
+ case "!": // already handled by the start
+ case "@": break // the default anyway
+ }
+ continue
+
+ case "|":
+ if (inClass || !patternListStack.length || escaping) {
+ re += "\\|"
+ escaping = false
+ continue
+ }
+
+ re += "|"
+ continue
+
+ // these are mostly the same in regexp and glob
+ case "[":
+ // swallow any state-tracking char before the [
+ clearStateChar()
+
+ if (inClass) {
+ re += "\\" + c
+ continue
+ }
+
+ inClass = true
+ classStart = i
+ reClassStart = re.length
+ re += c
+ continue
+
+ case "]":
+ // a right bracket shall lose its special
+ // meaning and represent itself in
+ // a bracket expression if it occurs
+ // first in the list. -- POSIX.2 2.8.3.2
+ if (i === classStart + 1 || !inClass) {
+ re += "\\" + c
+ escaping = false
+ continue
+ }
+
+ // finish up the class.
+ hasMagic = true
+ inClass = false
+ re += c
+ continue
+
+ default:
+ // swallow any state char that wasn't consumed
+ clearStateChar()
+
+ if (escaping) {
+ // no need
+ escaping = false
+ } else if (reSpecials[c]
+ && !(c === "^" && inClass)) {
+ re += "\\"
+ }
+
+ re += c
+
+ } // switch
+ } // for
+
+
+ // handle the case where we left a class open.
+ // "[abc" is valid, equivalent to "\[abc"
+ if (inClass) {
+ // split where the last [ was, and escape it
+ // this is a huge pita. We now have to re-walk
+ // the contents of the would-be class to re-translate
+ // any characters that were passed through as-is
+ var cs = pattern.substr(classStart + 1)
+ , sp = this.parse(cs, SUBPARSE)
+ re = re.substr(0, reClassStart) + "\\[" + sp[0]
+ hasMagic = hasMagic || sp[1]
+ }
+
+ // handle the case where we had a +( thing at the *end*
+ // of the pattern.
+ // each pattern list stack adds 3 chars, and we need to go through
+ // and escape any | chars that were passed through as-is for the regexp.
+ // Go through and escape them, taking care not to double-escape any
+ // | chars that were already escaped.
+ var pl
+ while (pl = patternListStack.pop()) {
+ var tail = re.slice(pl.reStart + 3)
+ // maybe some even number of \, then maybe 1 \, followed by a |
+ tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) {
+ if (!$2) {
+ // the | isn't already escaped, so escape it.
+ $2 = "\\"
+ }
+
+ // need to escape all those slashes *again*, without escaping the
+ // one that we need for escaping the | character. As it works out,
+ // escaping an even number of slashes can be done by simply repeating
+ // it exactly after itself. That's why this trick works.
+ //
+ // I am sorry that you have to see this.
+ return $1 + $1 + $2 + "|"
+ })
+
+ // console.error("tail=%j\n %s", tail, tail)
+ var t = pl.type === "*" ? star
+ : pl.type === "?" ? qmark
+ : "\\" + pl.type
+
+ hasMagic = true
+ re = re.slice(0, pl.reStart)
+ + t + "\\("
+ + tail
+ }
+
+ // handle trailing things that only matter at the very end.
+ clearStateChar()
+ if (escaping) {
+ // trailing \\
+ re += "\\\\"
+ }
+
+ // only need to apply the nodot start if the re starts with
+ // something that could conceivably capture a dot
+ var addPatternStart = false
+ switch (re.charAt(0)) {
+ case ".":
+ case "[":
+ case "(": addPatternStart = true
+ }
+
+ // if the re is not "" at this point, then we need to make sure
+ // it doesn't match against an empty path part.
+ // Otherwise a/* will match a/, which it should not.
+ if (re !== "" && hasMagic) re = "(?=.)" + re
+
+ if (addPatternStart) re = patternStart + re
+
+ // parsing just a piece of a larger pattern.
+ if (isSub === SUBPARSE) {
+ return [ re, hasMagic ]
+ }
+
+ // skip the regexp for non-magical patterns
+ // unescape anything in it, though, so that it'll be
+ // an exact match against a file etc.
+ if (!hasMagic) {
+ return globUnescape(pattern)
+ }
+
+ var flags = options.nocase ? "i" : ""
+ , regExp = new RegExp("^" + re + "$", flags)
+
+ regExp._glob = pattern
+ regExp._src = re
+
+ return regExp
+}
+
+minimatch.makeRe = function (pattern, options) {
+ return new Minimatch(pattern, options || {}).makeRe()
+}
+
+Minimatch.prototype.makeRe = makeRe
+function makeRe () {
+ if (this.regexp || this.regexp === false) return this.regexp
+
+ // at this point, this.set is a 2d array of partial
+ // pattern strings, or "**".
+ //
+ // It's better to use .match(). This function shouldn't
+ // be used, really, but it's pretty convenient sometimes,
+ // when you just want to work with a regex.
+ var set = this.set
+
+ if (!set.length) return this.regexp = false
+ var options = this.options
+
+ var twoStar = options.noglobstar ? star
+ : options.dot ? twoStarDot
+ : twoStarNoDot
+ , flags = options.nocase ? "i" : ""
+
+ var re = set.map(function (pattern) {
+ return pattern.map(function (p) {
+ return (p === GLOBSTAR) ? twoStar
+ : (typeof p === "string") ? regExpEscape(p)
+ : p._src
+ }).join("\\\/")
+ }).join("|")
+
+ // must match entire pattern
+ // ending in a * or ** will make it less strict.
+ re = "^" + re + "$"
+
+ // can match anything, as long as it's not this.
+ if (this.negate) re = "^(?!" + re + ").*$"
+
+ try {
+ return this.regexp = new RegExp(re, flags)
+ } catch (ex) {
+ return this.regexp = false
+ }
+}
+
+minimatch.match = function (list, pattern, options) {
+ var mm = new Minimatch(pattern, options)
+ list = list.filter(function (f) {
+ return mm.match(f)
+ })
+ if (options.nonull && !list.length) {
+ list.push(pattern)
+ }
+ return list
+}
+
+Minimatch.prototype.match = match
+function match (f, partial) {
+ // console.error("match", f, this.pattern)
+ // short-circuit in the case of busted things.
+ // comments, etc.
+ if (this.comment) return false
+ if (this.empty) return f === ""
+
+ if (f === "/" && partial) return true
+
+ var options = this.options
+
+ // first, normalize any slash-separated path parts.
+ // f = path.normalize(f)
+
+ // windows: need to use /, not \
+ // On other platforms, \ is a valid (albeit bad) filename char.
+ if (process.platform === "win32") {
+ f = f.split("\\").join("/")
+ }
+
+ // treat the test path as a set of pathparts.
+ f = f.split(slashSplit)
+ if (options.debug) {
+ console.error(this.pattern, "split", f)
+ }
+
+ // just ONE of the pattern sets in this.set needs to match
+ // in order for it to be valid. If negating, then just one
+ // match means that we have failed.
+ // Either way, return on the first hit.
+
+ var set = this.set
+ // console.error(this.pattern, "set", set)
+
+ for (var i = 0, l = set.length; i < l; i ++) {
+ var pattern = set[i]
+ var hit = this.matchOne(f, pattern, partial)
+ if (hit) {
+ return !this.negate
+ }
+ }
+
+ // didn't get any hits. this is success if it's a negative
+ // pattern, failure otherwise.
+ return this.negate
+}
+
+// set partial to true to test if, for example,
+// "/a/b" matches the start of "/*/b/*/d"
+// Partial means, if you run out of file before you run
+// out of pattern, then that's fine, as long as all
+// the parts match.
+Minimatch.prototype.matchOne = function (file, pattern, partial) {
+ var options = this.options
+
+ if (options.debug) {
+ console.error("matchOne",
+ { "this": this
+ , file: file
+ , pattern: pattern })
+ }
+
+ if (options.matchBase && pattern.length === 1) {
+ file = path.basename(file.join("/")).split("/")
+ }
+
+ if (options.debug) {
+ console.error("matchOne", file.length, pattern.length)
+ }
+
+ for ( var fi = 0
+ , pi = 0
+ , fl = file.length
+ , pl = pattern.length
+ ; (fi < fl) && (pi < pl)
+ ; fi ++, pi ++ ) {
+
+ if (options.debug) {
+ console.error("matchOne loop")
+ }
+ var p = pattern[pi]
+ , f = file[fi]
+
+ if (options.debug) {
+ console.error(pattern, p, f)
+ }
+
+ // should be impossible.
+ // some invalid regexp stuff in the set.
+ if (p === false) return false
+
+ if (p === GLOBSTAR) {
+ // "**"
+ // a/**/b/**/c would match the following:
+ // a/b/x/y/z/c
+ // a/x/y/z/b/c
+ // a/b/x/b/x/c
+ // a/b/c
+ // To do this, take the rest of the pattern after
+ // the **, and see if it would match the file remainder.
+ // If so, return success.
+ // If not, the ** "swallows" a segment, and try again.
+ // This is recursively awful.
+ // a/b/x/y/z/c
+ // - a matches a
+ // - doublestar
+ // - matchOne(b/x/y/z/c, b/**/c)
+ // - b matches b
+ // - doublestar
+ // - matchOne(x/y/z/c, c) -> no
+ // - matchOne(y/z/c, c) -> no
+ // - matchOne(z/c, c) -> no
+ // - matchOne(c, c) yes, hit
+ var fr = fi
+ , pr = pi + 1
+ if (pr === pl) {
+ // a ** at the end will just swallow the rest.
+ // We have found a match.
+ // however, it will not swallow /.x, unless
+ // options.dot is set.
+ // . and .. are *never* matched by **, for explosively
+ // exponential reasons.
+ for ( ; fi < fl; fi ++) {
+ if (file[fi] === "." || file[fi] === ".." ||
+ (!options.dot && file[fi].charAt(0) === ".")) return false
+ }
+ return true
+ }
+
+ // ok, let's see if we can swallow whatever we can.
+ WHILE: while (fr < fl) {
+ var swallowee = file[fr]
+ if (swallowee === "." || swallowee === ".." ||
+ (!options.dot && swallowee.charAt(0) === ".")) {
+ // console.error("dot detected!")
+ break WHILE
+ }
+
+ // XXX remove this slice. Just pass the start index.
+ if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
+ // found a match.
+ return true
+ } else {
+ // ** swallows a segment, and continue.
+ fr ++
+ }
+ }
+ // no match was found.
+ // However, in partial mode, we can't say this is necessarily over.
+ // If there's more *pattern* left, then
+ if (partial) {
+ // ran out of file
+ // console.error("\n>>> no match, partial?", file, fr, pattern, pr)
+ if (fr === fl) return true
+ }
+ return false
+ }
+
+ // something other than **
+ // non-magic patterns just have to match exactly
+ // patterns with magic have been turned into regexps.
+ var hit
+ if (typeof p === "string") {
+ if (options.nocase) {
+ hit = f.toLowerCase() === p.toLowerCase()
+ } else {
+ hit = f === p
+ }
+ if (options.debug) {
+ console.error("string match", p, f, hit)
+ }
+ } else {
+ hit = f.match(p)
+ if (options.debug) {
+ console.error("pattern match", p, f, hit)
+ }
+ }
+
+ if (!hit) return false
+ }
+
+ // Note: ending in / means that we'll get a final ""
+ // at the end of the pattern. This can only match a
+ // corresponding "" at the end of the file.
+ // If the file ends in /, then it can only match a
+ // a pattern that ends in /, unless the pattern just
+ // doesn't have any more for it. But, a/b/ should *not*
+ // match "a/b/*", even though "" matches against the
+ // [^/]*? pattern, except in partial mode, where it might
+ // simply not be reached yet.
+ // However, a/b/ should still satisfy a/*
+
+ // now either we fell off the end of the pattern, or we're done.
+ if (fi === fl && pi === pl) {
+ // ran out of pattern and filename at the same time.
+ // an exact hit!
+ return true
+ } else if (fi === fl) {
+ // ran out of file, but still had pattern left.
+ // this is ok if we're doing the match as part of
+ // a glob fs traversal.
+ return partial
+ } else if (pi === pl) {
+ // ran out of pattern, still have file left.
+ // this is only acceptable if we're on the very last
+ // empty segment of a file with a trailing slash.
+ // a/* should match a/b/
+ var emptyFileEnd = (fi === fl - 1) && (file[fi] === "")
+ return emptyFileEnd
+ }
+
+ // should be unreachable.
+ throw new Error("wtf?")
+}
+
+
+// replace stuff like \* with *
+function globUnescape (s) {
+ return s.replace(/\\(.)/g, "$1")
+}
+
+
+function regExpEscape (s) {
+ return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
+}
View
1  node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/.npmignore
@@ -0,0 +1 @@
+/node_modules
View
23 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/LICENSE
@@ -0,0 +1,23 @@
+Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
View
12 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/README.md
@@ -0,0 +1,12 @@
+# lru cache
+
+A cache object that deletes the least-recently-used items.
+
+Usage:
+
+ var LRU = require("lru-cache")
+ , cache = LRU(10) // max 10 items. default = Infinity
+ cache.set("key", "value")
+ cache.get("key") // "value"
+
+RTFS for more info.
View
100 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js
@@ -0,0 +1,100 @@
+;(function () { // closure for web browsers
+
+if (module) {
+ module.exports = LRUCache
+} else {
+ // just set the global for non-node platforms.
+ ;(function () { return this })().LRUCache = LRUCache
+}
+
+function hOP (obj, key) {
+ return Object.prototype.hasOwnProperty.call(obj, key)
+}
+
+function LRUCache (maxLength) {
+ if (!(this instanceof LRUCache)) {
+ return new LRUCache(maxLength)
+ }
+ var cache = {} // hash of items by key
+ , lruList = {} // list of items in order of use recency
+ , lru = 0 // least recently used
+ , mru = 0 // most recently used
+ , length = 0 // number of items in the list
+
+ // resize the cache when the maxLength changes.
+ Object.defineProperty(this, "maxLength",
+ { set : function (mL) {
+ if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity
+ maxLength = mL
+ // if it gets above double maxLength, trim right away.
+ // otherwise, do it whenever it's convenient.
+ if (length > maxLength) trim()
+ }
+ , get : function () { return maxLength }
+ , enumerable : true
+ })
+
+ this.maxLength = maxLength
+
+ Object.defineProperty(this, "length",
+ { get : function () { return length }
+ , enumerable : true
+ })
+
+ this.reset = function () {
+ cache = {}
+ lruList = {}
+ lru = 0
+ mru = 0
+ length = 0
+ }
+
+ this.set = function (key, value) {
+ if (hOP(cache, key)) {
+ this.get(key)
+ cache[key].value = value
+ return undefined
+ }
+ var hit = {key:key, value:value, lu:mru++}
+ lruList[hit.lu] = cache[key] = hit
+ length ++
+ if (length > maxLength) trim()
+ }
+
+ this.get = function (key) {
+ if (!hOP(cache, key)) return undefined
+ var hit = cache[key]
+ delete lruList[hit.lu]
+ if (hit.lu === lru) lruWalk()
+ hit.lu = mru ++
+ lruList[hit.lu] = hit
+ return hit.value
+ }
+
+ this.del = function (key) {
+ if (!hOP(cache, key)) return undefined
+ var hit = cache[key]
+ delete cache[key]
+ delete lruList[hit.lu]
+ if (hit.lu === lru) lruWalk()
+ length --
+ }
+
+ function lruWalk () {
+ // lru has been deleted, hop up to the next hit.
+ lru = Object.keys(lruList).shift()
+ }
+
+ function trim () {
+ if (length <= maxLength) return undefined
+ var prune = Object.keys(lruList).slice(0, length - maxLength)
+ for (var i = 0, l = (length - maxLength); i < l; i ++) {
+ delete cache[ lruList[prune[i]].key ]
+ delete lruList[prune[i]]
+ }
+ length = maxLength
+ lruWalk()
+ }
+}
+
+})()
View
35 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "lru-cache",
+ "description": "A cache object that deletes the least-recently-used items.",
+ "version": "1.0.5",
+ "author": {
+ "name": "Isaac Z. Schlueter",
+ "email": "i@izs.me"
+ },
+ "scripts": {
+ "test": "tap test"
+ },
+ "main": "lib/lru-cache.js",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/isaacs/node-lru-cache.git"
+ },
+ "devDependencies": {
+ "tap": "0.1"
+ },
+ "license": {
+ "type": "MIT",
+ "url": "http://github.com/isaacs/node-lru-cache/raw/master/LICENSE"
+ },
+ "_id": "lru-cache@1.0.5",
+ "dependencies": {},
+ "optionalDependencies": {},
+ "engines": {
+ "node": "*"
+ },
+ "_engineSupported": true,
+ "_npmVersion": "1.1.4",
+ "_nodeVersion": "v0.6.12",
+ "_defaultsLoaded": true,
+ "_from": "lru-cache@~1.0.5"
+}
View
93 node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/test/basic.js
@@ -0,0 +1,93 @@
+var test = require('tap').test
+ , LRU = require('../')
+
+test('basic', function (t) {
+ var cache = new LRU(10)
+ cache.set("key", "value")
+ t.equal(cache.get("key"), "value")
+ t.equal(cache.get("nada"), undefined)
+ t.equal(cache.length, 1)
+ t.equal(cache.maxLength, 10)
+ t.end()
+})
+
+test('least recently set', function (t) {
+ var cache = new LRU(2)
+ cache.set("a", "A")
+ cache.set("b", "B")
+ cache.set("c", "C")
+ t.equal(cache.get("c"), "C")
+ t.equal(cache.get("b"), "B")
+ t.equal(cache.get("a"), undefined)
+ t.end()
+})
+
+test('lru recently gotten', function (t) {
+ var cache = new LRU(2)
+ cache.set("a", "A")
+ cache.set("b", "B")
+ cache.get("a")
+ cache.set("c", "C")
+ t.equal(cache.get("c"), "C")
+ t.equal(cache.get("b"), undefined)
+ t.equal(cache.get("a"), "A")
+ t.end()
+})
+
+test('del', function (t) {
+ var cache = new LRU(2)
+ cache.set("a", "A")
+ cache.del("a")
+ t.equal(cache.get("a"), undefined)
+ t.end()
+})
+
+test('maxLength', function (t) {
+ var cache = new LRU(3)
+
+ // test changing the maxLength, verify that the LRU items get dropped.
+ cache.maxLength = 100
+ for (var i = 0; i < 100; i ++) cache.set(i, i)
+ t.equal(cache.length, 100)
+ for (var i = 0; i < 100; i ++) {
+ t.equal(cache.get(i), i)
+ }
+ cache.maxLength = 3
+ t.equal(cache.length, 3)
+ for (var i = 0; i < 97; i ++) {
+ t.equal(cache.get(i), undefined)
+ }
+ for (var i = 98; i < 100; i ++) {
+ t.equal(cache.get(i), i)
+ }
+
+ // now remove the maxLength restriction, and try again.
+ cache.maxLength = "hello"
+ for (var i = 0; i < 100; i ++) cache.set(i, i)
+ t.equal(cache.length, 100)
+ for (var i = 0; i < 100; i ++) {
+ t.equal(cache.get(i), i)
+ }
+ // should trigger an immediate resize
+ cache.maxLength = 3
+ t.equal(cache.length, 3)
+ for (var i = 0; i < 97; i ++) {
+ t.equal(cache.get(i), undefined)
+ }
+ for (var i = 98; i < 100; i ++) {
+ t.equal(cache.get(i), i)
+ }
+ t.end()
+})
+
+test('reset', function (t) {
+ var cache = new LRU(10)
+ cache.set("a", "A")
+ cache.set("b", "B")
+ cache.reset()
+ t.equal(cache.length, 0)
+ t.equal(cache.maxLength, 10)
+ t.equal(cache.get("a"), undefined)
+ t.equal(cache.get("b"), undefined)
+ t.end()
+})
View
40 node_modules/jshint/node_modules/minimatch/package.json
@@ -0,0 +1,40 @@
+{
+ "author": {
+ "name": "Isaac Z. Schlueter",
+ "email": "i@izs.me",
+ "url": "http://blog.izs.me"
+ },
+ "name": "minimatch",
+ "description": "a glob matcher in javascript",
+ "version": "0.2.0",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/isaacs/minimatch.git"
+ },
+ "main": "minimatch.js",
+ "scripts": {