Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

eslint

Package Overview
Dependencies
Maintainers
1
Versions
372
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

lib/formatters/stylish.js

3

conf/eslint.json

@@ -15,2 +15,3 @@ {

"no-comma-dangle": 2,
"no-cond-assign": 2,
"no-control-regex": 2,

@@ -28,2 +29,3 @@ "no-debugger": 2,

"no-extra-semi": 2,
"no-extra-strict": 2,
"no-func-assign": 2,

@@ -103,3 +105,2 @@ "no-floating-decimal": 0,

"strict": 2,
"unnecessary-strict": 2,
"use-isnan": 2,

@@ -106,0 +107,0 @@ "wrap-iife": 0,

@@ -42,3 +42,3 @@ /**

function getFiles(dir){
function getFiles(dir, configHelper){
var files = [];

@@ -49,2 +49,3 @@

} catch (ex){
/* istanbul ignore next too hard to make fs.stat fail */
return [];

@@ -55,2 +56,8 @@ }

stack.push(dir);
try {
configHelper.cacheExclusions(path.join.apply(path, stack));
} catch(e) {
/* istanbul ignore next Error handling doesn't need testing */
console.log(e.message);
}
fs.readdirSync(path.join.apply(path, stack)).forEach(function(file){

@@ -60,2 +67,7 @@ var filePath = path.join.apply(path, stack.concat([file])),

//if this file or directory is excluded from linting, skip over it.
if (configHelper.checkForExclusion(path.resolve(filePath))) {
return;
}
if (file[0] === ".") {

@@ -120,3 +132,3 @@ return;

config = configHelper.getConfig(filePath);
text = fs.readFileSync(path.resolve(filename), "utf8");
text = fs.readFileSync(path.resolve(filename), "utf8").replace(/^#![^\r\n]+[\r\n]/, "");
messages = eslint.verify(text, config);

@@ -166,3 +178,3 @@ } else {

if (isDirectory(file)) {
fullFileList = fullFileList.concat(getFiles(file));
fullFileList = fullFileList.concat(getFiles(file, configHelper));
} else {

@@ -169,0 +181,0 @@ fullFileList.push(file);

@@ -14,5 +14,9 @@ /**

environments = require("../conf/environments.json"),
util = require("./util");
util = require("./util"),
glob = require("glob"),
stripComments = require("strip-json-comments");
var existsSync = fs.existsSync || path.existsSync;
//------------------------------------------------------------------------------

@@ -23,2 +27,3 @@ // Constants

var LOCAL_CONFIG_FILENAME = ".eslintrc";
var ESLINT_IGNORE_FILENAME = ".eslintignore";

@@ -30,4 +35,43 @@

/**
* Check if a given directory contains .eslintignore
* files and if so, load and parse them
* @param {string} directory path
*/
function loadIgnoreFile(directory) {
var exclusions = [];
if (existsSync(path.resolve(directory, ESLINT_IGNORE_FILENAME))) {
//load .eslintignore file and JSON parse it
try {
exclusions = JSON.parse(fs.readFileSync(path.resolve(directory, ESLINT_IGNORE_FILENAME), "utf8"));
} catch (e) {
/* istanbul ignore next Error handling doesn't need tests*/
throw new Error("Could not load local .eslintignore file: " + path.resolve(directory, ESLINT_IGNORE_FILENAME));
}
}
return exclusions;
}
/**
* Load and parse a JSON config object from a file.
* @param {string} filePath the path to the JSON config file
* @return {object} the parsed config object (empty object if there was a parse error)
*/
function loadConfig(filePath) {
var config = {};
if (filePath) {
try {
config = JSON.parse(stripComments(fs.readFileSync(filePath, "utf8")));
} catch (e) {
console.error("Cannot read config file:", filePath);
console.error("Error: ", e.message);
}
}
return config;
}
/**
* Get a local config object.

@@ -41,9 +85,5 @@ * @param {string} directory the directory to start looking for a local config

/* istanbul ignore else Too complicated to create unittest*/
if (localConfigFile) {
try {
config = JSON.parse(fs.readFileSync(localConfigFile));
} catch (e) {
console.error("Cannot read config file:", localConfigFile);
console.error("Error: ", e.message);
}
config = loadConfig(localConfigFile);
}

@@ -70,2 +110,3 @@

this.cache = {};
this.exclusionsCache = {};
this.baseConfig = require(path.resolve(__dirname, "..", "conf", "eslint.json"));

@@ -76,3 +117,3 @@ this.baseConfig.format = options.format;

if (useConfig) {
this.useSpecificConfig = require(path.resolve(process.cwd(), useConfig));
this.useSpecificConfig = loadConfig(path.resolve(process.cwd(), useConfig));
}

@@ -84,12 +125,12 @@ }

* environments config (conf/environments.json) and eventually the user config.
* @param {string} directory the directory to start looking for a local config
* @param {string} filePath a file in whose directory we start looking for a local config
* @return {object} config object
*/
Config.prototype.getConfig = function (directory) {
Config.prototype.getConfig = function (filePath) {
var config,
userConfig,
envConfig = {};
envConfig = {},
directory = filePath ? path.dirname(filePath) : process.eslintCwd || process.cwd();
directory = path.dirname(directory);
config = this.cache[directory];
config = this.cache[directory];

@@ -138,4 +179,41 @@ if (config) {

/**
* Process given directory or file and cache ignore file if there's any
* @param {string} path to file or directory
*/
Config.prototype.cacheExclusions = function(directory) {
//check if there's an ignore file in the current directory and load it
var exclusions = this.exclusionsCache[directory],
me = this;
if (!exclusions) {
exclusions = loadIgnoreFile(directory);
if (exclusions.length > 0) {
//resolve globs and cache them
exclusions.forEach(function(pattern) {
if (pattern !== "") {
var matches = glob.sync(pattern, { cwd: directory });
if (matches) {
me.exclusionsCache[directory] = matches.map(function(match) { return path.resolve(directory, match); });
}
}
});
}
}
};
/**
* Check if the current file should not be processed
* @param {string} resolved file path
* return {boolean} if the file should be excluded
*/
Config.prototype.checkForExclusion = function(filePath) {
return Object.keys(this.exclusionsCache).some(function(directory) {
return this.exclusionsCache[directory].some(function(file) {
return file === filePath;
});
}, this);
};
/**
* Find a local config file, relative to a specified directory.

@@ -142,0 +220,0 @@ * @param {string} directory the directory to start searching from

@@ -128,2 +128,3 @@ /**

// TODO: Figures out if we can eliminate this initial sweep of comments
program.comments.forEach(function(comment) {

@@ -203,2 +204,5 @@ parseComment(comment, declaredGlobals);

// set unlimited listeners (see https://github.com/eslint/eslint/issues/524)
api.setMaxListeners(0);
/**

@@ -227,4 +231,4 @@ * Resets the internal state of the object.

var ast,
parseError = false;
var parseError = false,
ast;

@@ -282,9 +286,15 @@ if (!saveState) {

/* istanbul ignore else Too complicate to fake invalid rule*/
if (ruleCreator) {
rule = ruleCreator(new RuleContext(key, api, options));
try {
rule = ruleCreator(new RuleContext(key, api, options));
// add all the node types as listeners
Object.keys(rule).forEach(function(nodeType) {
api.on(nodeType, rule[nodeType]);
});
// add all the node types as listeners
Object.keys(rule).forEach(function(nodeType) {
api.on(nodeType, rule[nodeType]);
});
} catch(ex) {
throw new Error("Error while loading rule '" + key + "'.");
}
} else {

@@ -322,6 +332,40 @@ throw new Error("Definition for rule '" + key + "' was not found.");

enter: function(node) {
var comments = api.getComments(node),
leadingComments = comments.leading,
trailingComments = comments.trailing;
if (leadingComments) {
leadingComments.forEach(function(node) {
api.emit(node.type + "Comment", node);
});
}
api.emit(node.type, node);
if (trailingComments) {
trailingComments.forEach(function(node) {
api.emit(node.type + "Comment", node);
});
}
},
leave: function(node) {
var comments = api.getComments(node),
leadingComments = comments.leading,
trailingComments = comments.trailing;
if (trailingComments) {
trailingComments.forEach(function(node) {
api.emit(node.type + "Comment:after", node);
});
}
api.emit(node.type + ":after", node);
if (leadingComments) {
leadingComments.forEach(function(node) {
api.emit(node.type + "Comment:after", node);
});
}
}

@@ -339,3 +383,3 @@ });

* @param {ASTNode} node The AST node that the message relates to.
* @param {Object} [location] An object containing the error line and column
* @param {Object} [location] An object containing the error line and column
* numbers. If location is not provided the node's start location will

@@ -533,3 +577,3 @@ * be used.

api.defaults = function() {
return require("./conf/eslint.json");
return require("../conf/eslint.json");
};

@@ -536,0 +580,0 @@

@@ -67,3 +67,4 @@ /**

"severity=\"" + xmlEscape(getMessageType(message, rules)) + "\" " +
"message=\"" + xmlEscape(message.message) + "\" />";
"message=\"" + xmlEscape(message.message) +
(message.ruleId ? " (" + message.ruleId + ")" : "") + "\" />";
});

@@ -70,0 +71,0 @@

@@ -50,3 +50,3 @@ /**

(message.column || 0) + ", " + getMessageType(message, rules);
output += " - " + message.message + "\n";
output += " - " + message.message + (message.ruleId ? " (" + message.ruleId + ")" : "") + "\n";
});

@@ -53,0 +53,0 @@

@@ -62,3 +62,4 @@ /**

"evidence=\"" + escapeSpecialCharacters(message.source) + "\" " +
"reason=\"" + escapeSpecialCharacters(message.message) + "\" />";
"reason=\"" + escapeSpecialCharacters(message.message) +
(message.ruleId ? " (" + message.ruleId + ")" : "") + "\" />";
});

@@ -65,0 +66,0 @@

@@ -90,2 +90,3 @@ /**

output += " - " + escapeSpecialCharacters(message.message);
output += (message.ruleId ? " (" + message.ruleId + ")" : "");
output += "]]>";

@@ -92,0 +93,0 @@ output += "</" + type + ">";

@@ -33,3 +33,3 @@ /**

optimist.alias("f", "format");
optimist.default("f", "compact");
optimist.default("f", "stylish");
optimist.describe("f", "Use a specific output format.");

@@ -36,0 +36,0 @@

@@ -38,2 +38,6 @@ /**

exports.testClear = function() {
rules = Object.create(null);
};
exports.define = define;

@@ -40,0 +44,0 @@

@@ -6,2 +6,4 @@ /**

"use strict";
//------------------------------------------------------------------------------

@@ -13,3 +15,3 @@ // Rule Definition

"use strict";
var MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.";

@@ -20,25 +22,32 @@ //--------------------------------------------------------------------------

function checkBlockStartsAtIdentifier(node) {
var startLine = node.loc.start.line;
function checkBlock() {
var blockProperties = arguments;
return function(node) {
var tokens, block;
[].forEach.call(blockProperties, function(blockProp) {
block = node[blockProp];
if(block && block.type === "BlockStatement") {
tokens = context.getTokens(block, 1);
if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
context.report(node, MESSAGE);
}
}
});
};
}
// Checks for opening curly brace on FunctionDeclarations.
if (node.body && startLine !== node.body.loc.start.line) {
context.report(node, "Opening curly brace does not appear on the same line as the block identifier.");
function checkSwitchStatement(node) {
var tokens;
if(node.cases && node.cases.length) {
tokens = context.getTokens(node.cases[0], 2);
if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
context.report(node, MESSAGE);
}
} else {
tokens = context.getTokens(node);
tokens.pop();
if (tokens.pop().loc.start.line !== tokens.pop().loc.start.line) {
context.report(node, MESSAGE);
}
}
// Checks for opening curly brace on IfStatement, DoWhileStatement,
// WhileStatement, WithStatement, ForStatement, and ForInStatement.
if (node.consequent && startLine !== node.consequent.loc.start.line) {
context.report(node, "Opening curly brace does not appear on the same line as the block identifier.");
}
// Checks for opening curly brace on TryStatement.
if (node.block && startLine !== node.block.loc.start.line) {
context.report(node, "Opening curly brace does not appear on the same line as the block identifier.");
}
// Checks for opening curly on SwitchStatement.
if (node.discriminant && startLine !== node.cases[0].loc.start.line - 1) {
context.report(node, "Opening curly brace does not appear on the same line as the block identifier.");
}
}

@@ -51,13 +60,14 @@

return {
"FunctionDeclaration": checkBlockStartsAtIdentifier,
"IfStatement": checkBlockStartsAtIdentifier,
"SwitchStatement": checkBlockStartsAtIdentifier,
"TryStatement": checkBlockStartsAtIdentifier,
"DoWhileStatement": checkBlockStartsAtIdentifier,
"WhileStatement": checkBlockStartsAtIdentifier,
"WithStatement": checkBlockStartsAtIdentifier,
"ForStatement": checkBlockStartsAtIdentifier,
"ForInStatement": checkBlockStartsAtIdentifier
"FunctionDeclaration": checkBlock("body"),
"IfStatement": checkBlock("consequent", "alternate"),
"TryStatement": checkBlock("block", "finalizer"),
"CatchClause": checkBlock("body"),
"DoWhileStatement": checkBlock("body"),
"WhileStatement": checkBlock("body"),
"WithStatement": checkBlock("body"),
"ForStatement": checkBlock("body"),
"ForInStatement": checkBlock("body"),
"SwitchStatement": checkSwitchStatement
};
};

@@ -6,2 +6,3 @@ /**

"use strict";

@@ -14,18 +15,24 @@ //------------------------------------------------------------------------------

"use strict";
/**
* Creates a string that is made up of repeating a given string a certain
* number of times. This uses exponentiation of squares to achieve significant
* performance gains over the more traditional implementation of such
* functionality.
* @param {string} str The string to repeat.
* @param {int} num The number of times to repeat the string.
* @returns {string} The created string.
* @private
*/
function stringRepeat(str, num) {
var result = "";
for (num |= 0; num > 0; num >>>= 1, str += str) {
if (num & 1) {
result += str;
}
}
return result;
}
var tabWidth = context.options[1];
function stringRepeat(num) {
num = parseInt(num, 10);
var str = "",
i;
for (i = 0; i < tabWidth; i += 1) {
str += " ";
}
return str;
}
var maxLength = context.options[0],

@@ -41,16 +48,19 @@ tabString = stringRepeat(" ", tabWidth);

node.range[0] = 0;
var lines = context.getSource(node).split("\n"),
i,
line;
var lines = context.getSource(node);
// getSource might return null if fed an empty string
if(!lines) {
return;
}
for (i = 0; i < lines.length; i++) {
line = lines[i];
// Replace the tabs with the tab width
line = line.replace(/\t/g, tabString);
if (line.length > maxLength) {
context.report(node, "Line " + i + " exceeds the maximum line length of " + maxLength + ".");
}
}
// Replace the tabs
// Split (honors line-ending)
// Iterate
lines
.replace(/\t/g, tabString)
.split(/\r?\n/)
.forEach(function(line, i){
if (line.length > maxLength) {
context.report(node, { line: i + 1, col: 1 }, "Line " + (i + 1) + " exceeds the maximum line length of " + maxLength + ".");
}
});
}

@@ -57,0 +67,0 @@

@@ -22,7 +22,8 @@ /**

var items = node.properties || node.elements,
lastItem = items[items.length - 1];
// The last token in an object/array literal will always be a closing
// curly, so we check the second to last token for a comma.
if (secondToLastToken.value === ",") {
var items = node.properties || node.elements;
context.report(items[items.length - 1], "Trailing comma.");
if(secondToLastToken.value === "," && items.length && lastItem) {
context.report(lastItem, "Trailing comma.");
}

@@ -29,0 +30,0 @@ }

@@ -14,9 +14,22 @@ /**

var message = "Expected a conditional expression and instead saw an assignment.",
targetExpr = "AssignmentExpression";
function isParenthesised(node) {
var tokens = context.getTokens(node, 1, 1),
firstToken = tokens[0],
lastToken = tokens[tokens.length - 1];
return firstToken.value === "(" && firstToken.range[1] <= node.range[0] &&
lastToken.value === ")" && lastToken.range[0] >= node.range[1];
}
function isParenthesisedTwice(node) {
var tokens = context.getTokens(node, 2, 2),
firstToken = tokens[0],
lastToken = tokens[tokens.length - 1];
return isParenthesised(node) &&
firstToken.value === "(" && firstToken.range[1] <= node.range[0] &&
lastToken.value === ")" && lastToken.range[0] >= node.range[1];
}
function testForAssign(node) {
var type = node.test.type;
if (type === targetExpr) {
context.report(node, message);
if ("AssignmentExpression" === node.test.type && !isParenthesisedTwice(node.test)) {
context.report(node, "Expected a conditional expression and instead saw an assignment.");
}

@@ -23,0 +36,0 @@ }

@@ -5,2 +5,3 @@ /**

*/
"use strict";

@@ -13,10 +14,12 @@ //------------------------------------------------------------------------------

"use strict";
return {
return {
"BlockStatement": function(node) {
var ancestors = context.getAncestors(),
parentType = ancestors[ancestors.length - 1].type;
parent = ancestors[ancestors.length - 1],
parentType = parent.type,
isFinallyBlock = (parentType === "TryStatement") && (parent.finalizer === node);
if (parentType === "FunctionExpression" || parentType === "FunctionDeclaration") {
if (/FunctionExpression|FunctionDeclaration|CatchClause/.test(parentType) ||
(isFinallyBlock && !parent.handlers.length)) {
return;

@@ -23,0 +26,0 @@ }

@@ -6,2 +6,4 @@ /**

"use strict";
//------------------------------------------------------------------------------

@@ -13,4 +15,2 @@ // Rule Definition

"use strict";
var allowUnusedGlobals = context.options[0] === "all" ? false : true;

@@ -20,7 +20,15 @@

function populateVariables() {
var scope = context.getScope();
function populateVariables(node) {
var scope = context.getScope(),
functionName = node && node.id && node.id.name,
parent = context.getAncestors().pop(),
// check for function foo(){}.bind(this)
functionNameUsed = parent && parent.type === "MemberExpression";
scope.variables.forEach(function(variable) {
//filter out global variables that we add as part of eslint or arguments variable
if (variable.identifiers.length > 0) {
//make sure that this variable is not already in the array

@@ -30,3 +38,8 @@ if (!variables.some(function(storedVariable) {

})) {
variables.push({name: variable.name, node: variable.identifiers[0]});
variables.push({
name: variable.name,
node: variable.identifiers[0],
used: (variable.name === functionName) && functionNameUsed
});
}

@@ -46,5 +59,7 @@ }

var scopeVariable = [];
function filter(variable) {
return variable.name === name;
}
while (scopeVariable.length === 0) {

@@ -136,2 +151,3 @@ scopeVariable = scope.variables.filter(filter);

},
"Program:after": function() {

@@ -138,0 +154,0 @@ var unused = variables.filter(function(variable) {

@@ -45,3 +45,4 @@ /**

var assert = require("chai").assert,
eslint = require("../eslint");
eslint = require("../eslint"),
util = require("util");

@@ -70,3 +71,4 @@ //------------------------------------------------------------------------------

assert.equal(messages.length, 0, "Should have no errors");
assert.equal(messages.length, 0, util.format("Should have no errors but had %d: %s",
messages.length, util.inspect(messages)));
}

@@ -89,3 +91,5 @@

} else {
assert.equal(messages.length, item.errors.length, "Number of errors");
assert.equal(messages.length, item.errors.length,
util.format("Should have %d errors but had %d: %s",
item.errors.length, messages.length, util.inspect(messages)));

@@ -92,0 +96,0 @@ if (messages.length === item.errors.length) {

{
"name": "eslint",
"version": "0.2.0",
"version": "0.3.0",
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",

@@ -16,3 +16,4 @@ "description": "An Esprima-based pattern checker for JavaScript.",

"major": "node Makefile.js major",
"bundle": "bash scripts/bundle.sh"
"gensite": "node Makefile.js gensite",
"browserify": "node Makefile.js browserify"
},

@@ -28,3 +29,3 @@ "files": [

"type": "git",
"url": "https://github.com/nzakas/eslint"
"url": "https://github.com/eslint/eslint"
},

@@ -35,7 +36,10 @@ "dependencies": {

"esprima": "*",
"escope": "1.0.0"
"escope": "1.0.0",
"glob": "~3.2.7",
"text-table": "~0.2.0",
"chalk": "~0.4.0",
"strip-json-comments": "~0.1.1"
},
"devDependencies": {
"sinon": "*",
"commonjs-everywhere": "~0.9.0",
"sinon": "1.7.3",
"mocha": "~1.13.0",

@@ -45,4 +49,7 @@ "chai": "~1.8.1",

"jsonlint": "~1.6.0",
"jshint": "~2.3",
"istanbul": "~0.1"
"istanbul": "~0.2.3",
"dateformat": "~1.0.7-1.2.3",
"browserify": "~3.20.0",
"mocha-phantomjs": "~3.3.1",
"phantomjs": "~1.9.2-6"
},

@@ -58,4 +65,4 @@ "keywords": [

"type": "MIT",
"url": "https://github.com/nzakas/eslint/blob/master/LICENSE"
"url": "https://github.com/eslint/eslint/blob/master/LICENSE"
}
}

@@ -1,2 +0,2 @@

[![Build Status](https://secure.travis-ci.org/nzakas/eslint.png?branch=master)](http://travis-ci.org/nzakas/eslint)
[![Build Status](https://secure.travis-ci.org/eslint/eslint.png?branch=master)](http://travis-ci.org/eslint/eslint)

@@ -38,6 +38,10 @@ # ESLint

Our first goal for ESLint is to hit feature/rule and stability parity with JSHint so that developers can start using ESLint as part of their production toolchain. The master list of JSHint features to be implemented is maintained in this [Google Docs spreadsheet](https://docs.google.com/spreadsheet/lv?key=0Ap5QGaRT4AJ_dGV6VXBlMEw3NHhVRl9vQ0lIX2FnVlE&usp=sharing). To read about plans beyond parity with JSHint, check out the [ESLint Roadmap](https://github.com/nzakas/eslint/wiki/Release-goals).
Our first goal for ESLint is to hit rule and stability parity with JSHint so that developers can start using ESLint as part of their production toolchain. The master list of JSHint features to be implemented is maintained in this [Google Docs spreadsheet](https://docs.google.com/spreadsheet/lv?key=0Ap5QGaRT4AJ_dGV6VXBlMEw3NHhVRl9vQ0lIX2FnVlE&usp=sharing). To read about plans beyond parity with JSHint, check out the [ESLint Roadmap](https://github.com/eslint/eslint/wiki/Release-goals).
### What about ECMAScript 6 support?
At the moment, ES6 support is turned off due to the experimental nature of the support in Esprima. There is basic support for `let` and `const`, but aside from that, the rest of the features are unsupported. We will re-evaluate ES6 support after v0.5.0.
### Where to ask for help?
Join our [Mailing List](https://groups.google.com/group/eslint)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc