Comparing version 2.4.4 to 2.5.0
{ | ||
"name": "jshint", | ||
"version": "2.4.4", | ||
"version": "2.5.0", | ||
"homepage": "http://jshint.com/", | ||
@@ -42,3 +42,4 @@ "description": "Static analysis tool for JavaScript", | ||
"console-browserify": "0.1.x", | ||
"exit": "0.1.x" | ||
"exit": "0.1.x", | ||
"strip-json-comments": "0.1.x" | ||
}, | ||
@@ -57,16 +58,2 @@ | ||
"jshintConfig": { | ||
"boss": true, | ||
"node": true, | ||
"strict": true, | ||
"white": true, | ||
"smarttabs": true, | ||
"maxlen": 100, | ||
"newcap": false, | ||
"undef": true, | ||
"unused": true, | ||
"onecase": true, | ||
"indent": 2 | ||
}, | ||
"licenses": [ | ||
@@ -73,0 +60,0 @@ { |
@@ -13,5 +13,5 @@ JSHint, A Static Code Analysis Tool for JavaScript | ||
JSHint is a community-driven tool to detect errors and potential problems | ||
in JavaScript code and to enforce your team’s coding conventions. It is | ||
very flexible so you can easily adjust it to your particular coding guidelines | ||
and the environment you expect your code to execute in. | ||
in JavaScript code. It is very flexible so you can easily adjust it to your | ||
particular coding guidelines and the environment you expect your code to | ||
execute in. | ||
@@ -18,0 +18,0 @@ #### JSHint 2.x versus JSHint 3 |
178
src/cli.js
"use strict"; | ||
var _ = require("underscore"); | ||
var cli = require("cli"); | ||
var path = require("path"); | ||
var shjs = require("shelljs"); | ||
var minimatch = require("minimatch"); | ||
var htmlparser = require("htmlparser2"); | ||
var exit = require("exit"); | ||
var JSHINT = require("./jshint.js").JSHINT; | ||
var defReporter = require("./reporters/default").reporter; | ||
var _ = require("underscore"); | ||
var cli = require("cli"); | ||
var path = require("path"); | ||
var shjs = require("shelljs"); | ||
var minimatch = require("minimatch"); | ||
var htmlparser = require("htmlparser2"); | ||
var exit = require("exit"); | ||
var stripJsonComments = require("strip-json-comments"); | ||
var JSHINT = require("./jshint.js").JSHINT; | ||
var defReporter = require("./reporters/default").reporter; | ||
@@ -19,2 +20,5 @@ var OPTIONS = { | ||
"exclude-path": ["exclude-path", "Pass in a custom jshintignore file path", "string", null], | ||
"filename": ["filename", | ||
"Pass in a filename when using STDIN to emulate config lookup for that file name", | ||
"string", null], | ||
"verbose": ["verbose", "Show message codes"], | ||
@@ -63,25 +67,2 @@ "show-non-errors": ["show-non-errors", "Show additional data generated by jshint"], | ||
/** | ||
* Removes JavaScript comments from a string by replacing | ||
* everything between block comments and everything after | ||
* single-line comments in a non-greedy way. | ||
* | ||
* English version of the regex: | ||
* match '/*' | ||
* then match zero or more instances of any character (incl. \n) | ||
* except for instances of '* /' (without a space, obv.) | ||
* then match '* /' (again, without a space) | ||
* | ||
* @param {string} str a string with potential JavaScript comments. | ||
* @returns {string} a string without JavaScript comments. | ||
*/ | ||
function removeComments(str) { | ||
str = str || ""; | ||
str = str.replace(/\/\*(?:(?!\*\/)[\s\S])*\*\//g, ""); | ||
str = str.replace(/\/\/[^\n\r]*/g, ""); // Everything after '//' | ||
return str; | ||
} | ||
/** | ||
* Tries to find a configuration file in either project directory | ||
@@ -303,5 +284,5 @@ * or in the home directory. Configuration files are named | ||
lines = lines.map(function (line) { | ||
return line.replace(startOffset, ''); | ||
return line.replace(startOffset, ""); | ||
}); | ||
data = lines.join('\n'); | ||
data = lines.join("\n"); | ||
} | ||
@@ -319,2 +300,84 @@ | ||
/** | ||
* Crude version of source maps: extract how much JavaSscript in HTML | ||
* was shifted based on first JS line. For example if first js line | ||
* is offset by 4 spaces, each line in this js fragment will have offset 4 | ||
* to restore the original column. | ||
* | ||
* @param {string} code a piece of code | ||
* @param {string} when 'always' will extract the JS code, no matter what. | ||
* 'never' won't do anything. 'auto' will check if the code looks like HTML | ||
* before extracting it. | ||
* | ||
* @return {Array} extracted offsets | ||
*/ | ||
function extractOffsets(code, when) { | ||
// A JS file won't start with a less-than character, whereas a HTML file | ||
// should always start with that. | ||
if (when !== "always" && (when !== "auto" || !/^\s*</.test(code))) | ||
return; | ||
var inscript = false; | ||
var index = 0; | ||
var lineCounter = 0; | ||
var startOffset; | ||
var offsets = []; | ||
// Test if current tag is a valid <script> tag. | ||
function onopen(name, attrs) { | ||
if (name !== "script") | ||
return; | ||
if (attrs.type && !/text\/javascript/.test(attrs.type.toLowerCase())) | ||
return; | ||
// Mark that we're inside a <script> a tag and push all new lines | ||
// in between the last </script> tag and this <script> tag to preserve | ||
// location information. | ||
inscript = true; | ||
var fragment = code.slice(index, parser.endIndex); | ||
var n = fragment.match(/\n\r|\n|\r/g).length; | ||
lineCounter += n; | ||
startOffset = null; | ||
} | ||
function onclose(name) { | ||
if (name !== "script" || !inscript) | ||
return; | ||
inscript = false; | ||
index = parser.startIndex; | ||
startOffset = null; | ||
} | ||
function ontext(data) { | ||
if (!inscript) | ||
return; | ||
var lines = data.split(/\n\r|\n|\r/); | ||
if (!startOffset) { | ||
lines.some(function (line) { | ||
if (!line) return; | ||
startOffset = /^(\s*)/.exec(line)[1]; | ||
return true; | ||
}); | ||
} | ||
// check for startOffset again to remove leading white space from first line | ||
lines.forEach(function () { | ||
lineCounter += 1; | ||
if (startOffset) { | ||
offsets[lineCounter] = startOffset.length; | ||
} else { | ||
offsets[lineCounter] = 0; | ||
} | ||
}); | ||
} | ||
var parser = new htmlparser.Parser({ onopentag: onopen, onclosetag: onclose, ontext: ontext }); | ||
parser.parseComplete(code); | ||
return offsets; | ||
} | ||
/** | ||
* Recursively gather all files that need to be linted, | ||
@@ -383,3 +446,14 @@ * excluding those that user asked to ignore. | ||
if (config.overrides) { | ||
if (file) { | ||
_.each(config.overrides, function (options, pattern) { | ||
if ((new RegExp(pattern)).test(file)) _.extend(config, options); | ||
}); | ||
} | ||
delete config.overrides; | ||
} | ||
delete config.dirname; | ||
buffer.push(code); | ||
@@ -410,2 +484,9 @@ buffer = buffer.join("\n"); | ||
/** | ||
* Returns a configuration file or nothing, if it can't be found. | ||
*/ | ||
getConfig: function (fp) { | ||
return loadNpmConfig(fp) || exports.loadConfig(findConfig(fp)); | ||
}, | ||
/** | ||
* Loads and parses a configuration file. | ||
@@ -427,3 +508,3 @@ * | ||
try { | ||
var config = JSON.parse(removeComments(shjs.cat(fp))); | ||
var config = JSON.parse(stripJsonComments(shjs.cat(fp))); | ||
config.dirname = path.dirname(fp); | ||
@@ -492,3 +573,12 @@ | ||
cli.withStdin(function (code) { | ||
lint(extract(code, opts.extract), results, opts.config || {}, data); | ||
var config = opts.config; | ||
if (opts.filename && !config) { | ||
var filename = path.resolve(opts.filename); | ||
config = loadNpmConfig(filename) || | ||
exports.loadConfig(findConfig(filename)); | ||
} | ||
config = config || {}; | ||
lint(extract(code, opts.extract), results, config, data); | ||
(opts.reporter || defReporter)(results, data, { verbose: opts.verbose }); | ||
@@ -502,3 +592,3 @@ cb(results.length === 0); | ||
files.forEach(function (file) { | ||
var config = opts.config || loadNpmConfig(file) || exports.loadConfig(findConfig(file)); | ||
var config = opts.config || exports.getConfig(file); | ||
var code; | ||
@@ -514,2 +604,15 @@ | ||
lint(extract(code, opts.extract), results, config, data, file); | ||
if (results.length) { | ||
var offsets = extractOffsets(code, opts.extract); | ||
if (offsets && offsets.length) { | ||
results.forEach(function (errorInfo) { | ||
var line = errorInfo.error.line; | ||
if (line >= 0 && line < offsets.length) { | ||
var offset = +offsets[line]; | ||
errorInfo.error.character += offset; | ||
} | ||
}); | ||
} | ||
} | ||
}); | ||
@@ -603,2 +706,3 @@ | ||
extract: options.extract, | ||
filename: options.filename, | ||
useStdin: {"-": true, "/dev/stdin": true}[args[args.length - 1]] | ||
@@ -605,0 +709,0 @@ }, done)); |
106
src/lex.js
@@ -31,3 +31,4 @@ /* | ||
BooleanLiteral: 8, | ||
RegExp: 9 | ||
RegExp: 9, | ||
TemplateLiteral: 10 | ||
}; | ||
@@ -849,2 +850,58 @@ | ||
/* | ||
* Extract a template literal out of the next sequence of characters | ||
* and/or lines or return 'null' if its not possible. Since template | ||
* literals can span across multiple lines, this method has to move | ||
* the char pointer. | ||
*/ | ||
scanTemplateLiteral: function () { | ||
// String must start with a backtick. | ||
if (!state.option.esnext || this.peek() !== "`") { | ||
return null; | ||
} | ||
var startLine = this.line; | ||
var startChar = this.char; | ||
var jump = 1; | ||
var value = ""; | ||
// For now, do not perform any linting of the content of the template | ||
// string. Just skip until the next backtick is found. | ||
this.skip(); | ||
while (this.peek() !== "`") { | ||
while (this.peek() === "") { | ||
// End of line --- For template literals in ES6, no backslash is | ||
// required to precede newlines. | ||
if (!this.nextLine()) { | ||
this.trigger("error", { | ||
code: "E052", | ||
line: startLine, | ||
character: startChar | ||
}); | ||
return { | ||
type: Token.TemplateLiteral, | ||
value: value, | ||
isUnclosed: true | ||
}; | ||
} | ||
value += "\n"; | ||
} | ||
// TODO: do more interesting linting here, similar to string literal | ||
// linting. | ||
var char = this.peek(); | ||
this.skip(jump); | ||
value += char; | ||
} | ||
this.skip(); | ||
return { | ||
type: Token.TemplateLiteral, | ||
value: value, | ||
isUnclosed: false | ||
}; | ||
}, | ||
/* | ||
* Extract a string out of the next sequence of characters and/or | ||
@@ -1231,22 +1288,2 @@ * lines or return 'null' if its not possible. Since strings can | ||
/* | ||
* Scan for any occurence of mixed tabs and spaces. If smarttabs option | ||
* is on, ignore tabs followed by spaces. | ||
* | ||
* Tabs followed by one space followed by a block comment are allowed. | ||
*/ | ||
scanMixedSpacesAndTabs: function () { | ||
var at, match; | ||
if (state.option.smarttabs) { | ||
// Negative look-behind for "//" | ||
match = this.input.match(/(\/\/|^\s?\*)? \t/); | ||
at = match && !match[1] ? 0 : -1; | ||
} else { | ||
at = this.input.search(/ \t|\t [^\*]/); | ||
} | ||
return at; | ||
}, | ||
/* | ||
* Scan for any occurence of non-breaking spaces. Non-breaking spaces | ||
@@ -1284,8 +1321,2 @@ * can be mistakenly typed on OS X with option-space. Non UTF-8 web | ||
} | ||
if (this.peek() === "") { // EOL | ||
if (!/^\s*$/.test(this.getLines()[this.line - 1]) && state.option.trailing) { | ||
this.trigger("warning", { code: "W102", line: this.line, character: start }); | ||
} | ||
} | ||
} | ||
@@ -1297,3 +1328,4 @@ | ||
var match = this.scanComments() || | ||
this.scanStringLiteral(checks); | ||
this.scanStringLiteral(checks) || | ||
this.scanTemplateLiteral(); | ||
@@ -1325,4 +1357,3 @@ if (match) { | ||
* Switch to the next line and reset all char pointers. Once | ||
* switched, this method also checks for mixed spaces and tabs | ||
* and other minor warnings. | ||
* switched, this method also checks for other minor warnings. | ||
*/ | ||
@@ -1368,7 +1399,2 @@ nextLine: function () { | ||
char = this.scanMixedSpacesAndTabs(); | ||
if (char >= 0) { | ||
this.trigger("warning", { code: "W099", line: this.line, character: char + 1 }); | ||
} | ||
this.input = this.input.replace(/\t/g, state.tab); | ||
@@ -1539,2 +1565,12 @@ char = this.scanUnsafeChars(); | ||
return create("(string)", token.value); | ||
case Token.TemplateLiteral: | ||
this.trigger("Template", { | ||
line: this.line, | ||
char: this.char, | ||
from: this.from, | ||
value: token.value | ||
}); | ||
return create("(template)", token.value); | ||
case Token.Identifier: | ||
@@ -1541,0 +1577,0 @@ this.trigger("Identifier", { |
@@ -69,3 +69,4 @@ "use strict"; | ||
E050: "Mozilla requires the yield expression to be parenthesized here.", | ||
E051: "Regular parameters cannot come after default parameters." | ||
E051: "Regular parameters cannot come after default parameters.", | ||
E052: "Unclosed template literal." | ||
}; | ||
@@ -80,11 +81,11 @@ | ||
W006: "Confusing minuses.", | ||
W007: "Confusing pluses.", | ||
W007: "Confusing plusses.", | ||
W008: "A leading decimal point can be confused with a dot: '{a}'.", | ||
W009: "The array literal notation [] is preferable.", | ||
W010: "The object literal notation {} is preferable.", | ||
W011: "Unexpected space after '{a}'.", | ||
W012: "Unexpected space before '{a}'.", | ||
W013: "Missing space after '{a}'.", | ||
W011: null, | ||
W012: null, | ||
W013: null, | ||
W014: "Bad line breaking before '{a}'.", | ||
W015: "Expected '{a}' to have an indentation at {b} instead at {c}.", | ||
W015: null, | ||
W016: "Unexpected use of '{a}'.", | ||
@@ -156,3 +157,3 @@ W017: "Bad operand.", | ||
W080: "It's not necessary to initialize '{a}' to 'undefined'.", | ||
W081: "Too many var statements.", | ||
W081: null, | ||
W082: "Function declarations should not be placed in blocks. " + | ||
@@ -177,6 +178,6 @@ "Use a function expression or move the statement to the top of " + | ||
W098: "'{a}' is defined but never used.", | ||
W099: "Mixed spaces and tabs.", | ||
W099: null, | ||
W100: "This character may get silently deleted by one or more browsers.", | ||
W101: "Line is too long.", | ||
W102: "Trailing whitespace.", | ||
W102: null, | ||
W103: "The '{a}' property is deprecated.", | ||
@@ -183,0 +184,0 @@ W104: "'{a}' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).", |
@@ -1,2 +0,2 @@ | ||
/*jshint boss: true, rhino: true, unused: true, undef: true, white: true, quotmark: double */ | ||
/*jshint boss: true, rhino: true, unused: true, undef: true, quotmark: double */ | ||
/*global JSHINT, readFully */ | ||
@@ -3,0 +3,0 @@ |
@@ -21,4 +21,6 @@ "use strict"; | ||
this.cache = {}; // Node.JS doesn't have Map. Sniff. | ||
this.ignoreLinterErrors = false; // Blank out non-multi-line-commented | ||
// lines when ignoring linter errors | ||
this.ignoredLines = {}; | ||
// Blank out non-multi-line-commented lines when ignoring linter errors | ||
this.ignoreLinterErrors = false; | ||
} | ||
@@ -25,0 +27,0 @@ }; |
@@ -38,30 +38,2 @@ "use strict"; | ||
// Check for dangling underscores. | ||
linter.on("Identifier", function style_scanDangling(data) { | ||
if (!linter.getOption("nomen")) { | ||
return; | ||
} | ||
// Underscore.js | ||
if (data.name === "_") { | ||
return; | ||
} | ||
// In Node, __dirname and __filename should be ignored. | ||
if (linter.getOption("node")) { | ||
if (/^(__dirname|__filename)$/.test(data.name) && !data.isProperty) { | ||
return; | ||
} | ||
} | ||
if (/^(_+.*|.*_+)$/.test(data.name)) { | ||
linter.warn("W105", { | ||
line: data.line, | ||
char: data.from, | ||
data: [ "dangling '_'", data.name ] | ||
}); | ||
} | ||
}); | ||
// Check that all identifiers are using camelCase notation. | ||
@@ -172,2 +144,2 @@ // Exceptions: names like MY_VAR and _myVar. | ||
}); | ||
}; | ||
}; |
@@ -29,3 +29,2 @@ // jshint -W001 | ||
Math : false, | ||
Map : false, | ||
Number : false, | ||
@@ -38,3 +37,2 @@ Object : false, | ||
RegExp : false, | ||
Set : false, | ||
String : false, | ||
@@ -44,5 +42,13 @@ SyntaxError : false, | ||
URIError : false, | ||
WeakMap : false | ||
}; | ||
exports.newEcmaIdentifiers = { | ||
Set : false, | ||
Map : false, | ||
WeakMap : false, | ||
WeakSet : false, | ||
Proxy : false, | ||
Promise : false | ||
}; | ||
// Global variables commonly provided by a web browser environment. | ||
@@ -147,2 +153,3 @@ | ||
NodeFilter : false, | ||
NodeList : false, | ||
navigator : false, | ||
@@ -604,1 +611,15 @@ onbeforeunload : true, | ||
exports.mocha = { | ||
// BDD | ||
describe : false, | ||
it : false, | ||
before : false, | ||
after : false, | ||
beforeEach : false, | ||
afterEach : false, | ||
// TDD | ||
suite : false, | ||
test : false, | ||
setup : false, | ||
teardown : false | ||
}; |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
686729
8
57607
+ Addedstrip-json-comments@0.1.x
+ Addedstrip-json-comments@0.1.3(transitive)