From 53a03ef8faf14d84cdf076471b2dddd04a5a59f4 Mon Sep 17 00:00:00 2001 From: Evan Goer Date: Mon, 15 Jul 2013 21:04:02 -0700 Subject: [PATCH 1/4] Add wiki files to docs directory --- docs/About.md | 20 + docs/Architecture.md | 15 + docs/Code-Conventions.md | 908 ++++++++++++++++++++++++++++++++ docs/Command-line-interface.md | 79 +++ docs/Contributing.md | 39 ++ docs/Developer-Guide.md | 33 ++ docs/Development-Environment.md | 36 ++ docs/Home.md | 19 + docs/No-debugger.md | 17 + docs/No-empty.md | 25 + docs/No-unreachable.md | 13 + docs/Quote-props.md | 78 +++ docs/Rules.md | 40 ++ docs/Source-Code.md | 37 ++ docs/Unit-Tests.md | 7 + docs/Working-with-Rules.md | 152 ++++++ docs/new-cap.md | 25 + docs/no-arg.md | 34 ++ docs/no-console.md | 33 ++ docs/use-isnan.md | 5 + 20 files changed, 1615 insertions(+) create mode 100644 docs/About.md create mode 100644 docs/Architecture.md create mode 100644 docs/Code-Conventions.md create mode 100644 docs/Command-line-interface.md create mode 100644 docs/Contributing.md create mode 100644 docs/Developer-Guide.md create mode 100644 docs/Development-Environment.md create mode 100644 docs/Home.md create mode 100644 docs/No-debugger.md create mode 100644 docs/No-empty.md create mode 100644 docs/No-unreachable.md create mode 100644 docs/Quote-props.md create mode 100644 docs/Rules.md create mode 100644 docs/Source-Code.md create mode 100644 docs/Unit-Tests.md create mode 100644 docs/Working-with-Rules.md create mode 100644 docs/new-cap.md create mode 100644 docs/no-arg.md create mode 100644 docs/no-console.md create mode 100644 docs/use-isnan.md diff --git a/docs/About.md b/docs/About.md new file mode 100644 index 000000000000..99e4725eac87 --- /dev/null +++ b/docs/About.md @@ -0,0 +1,20 @@ +ESLint is an open source project originally created by Nicholas C. Zakas in June 2013. The goal of ESLint is to provide a pluggable linting utility for JavaScript. While [JSHint](http://jshint.com) and [JSLint](http://jslint.com) dominate JavaScript linting, neither one provides an API for plugging in your own rules. This means that if you need a new rule, you need to write it and get it accepted into the released product. That's lousy if you need to quickly add something to your build system or even if you need company-specific rules. + +ESLint is designed to have all rules completely pluggable. The default rules are written just like any plugin rules would be. They can all follow the same pattern, both for the rules themselves as well as tests. While ESLint will ship with some built-in rules for compatibility with JSHint and JSLint, you'll be able to dynamically load rules at any point in time. + +ESLint is written using Node.js to provide a fast runtime environment and easy installation via [npm](http://npmjs.org). + +## Philosophy + +Every rule: + +* Is standalone +* Can be able to be turned off or on (nothing can be deemed "too important to turn off") +* Can be set to be a warning or error individually +* Is turned on by providing a non-zero number and off by providing zero + +Additionally: + +* The only "error" that ships with ESLint is a parser error +* Not all rules bundled with ESLint are enabled by default +* Bundled rules that are enabled are set as warnings (not errors) \ No newline at end of file diff --git a/docs/Architecture.md b/docs/Architecture.md new file mode 100644 index 000000000000..bbab7c12a7ef --- /dev/null +++ b/docs/Architecture.md @@ -0,0 +1,15 @@ +At a high level, there are a few key parts to ESLint: + +* `bin/eslint.js` - this is the file that actually gets executed with the command line utility. It's a dumb wrapper that does nothing more than bootstrap ESLint, passing the command line arguments to `cli`. This is intentionally small so as not to require heavy testing. +* `lib/cli.js` - this is the heart of the ESLint CLI. It takes an array of arguments and then uses `eslint` to execute the commands. By keeping this as a separate utility, it allows others to effectively call ESLint from within another Node.js program as if it were done on the command line. The main call is `cli.execute()`. This is also the part that does all the file reading, directory traversing, input, and output. +* `lib/eslint.js` - this is the core `eslint` object that does code verifying based on configuration options. This file does not file I/O and does not interact with the `console` at all. For other Node.js programs that have JavaScript text to verify, they would be able to use this interface directly. + +## The cli Object + +TODO + +## The eslint Object + +The main method of the `eslint` object is `verify()` and accepts two arguments: the source text to verify and a configuration object (the baked configuration of the given configuration file plus command line options). The method first parses the given text with Esprima and retrieves the AST. The AST is produced with both line/column and range locations which are useful for reporting location of issues and retrieving the source text related to an AST node, respectively. + +Once the AST is available, `estraverse` is used to traverse the AST from top to bottom. At each node, the `eslint` object emits an event that has the same name as the node type (i.e., "Identifier", "WithStatement", etc.). On the way back up the subtree, an event is emitted with the AST type name and suffixed with ":after", such as "Identifier:after" - this allows rules to take action both on the way down and on the way up in the traversal. Each event is emitted with the appropriate AST node available. \ No newline at end of file diff --git a/docs/Code-Conventions.md b/docs/Code-Conventions.md new file mode 100644 index 000000000000..e24274e43f2b --- /dev/null +++ b/docs/Code-Conventions.md @@ -0,0 +1,908 @@ +Programming language style guides are important for the long-term maintainability of software. This guide is based on the [Code Conventions for the Java Programming Language](http:// java.sun.com/docs/codeconv/) and [Douglas Crockford's Code Conventions for the JavaScript Programming Language](http://javascript.crockford.com/code.html). Modifications have been made due to my personal experience and preferences. + +## Indentation + +Each indentation level is made up of four spaces. Do not use tabs. + + // Good + if (true) { + doSomething(); + } + +## Line Length + +Each line should be no longer than 80 characters. If a line goes longer than 80 characters, it should be wrapped after an operator (comma, plus, etc.). The following line should be indented two levels (eight characters). + + // Good + doSomething(argument1, argument2, argument3, argument4, + argument5); + + // Bad: Following line only indented four spaces + doSomething(argument1, argument2, argument3, argument4, + argument5); + + // Bad: Breaking before operator + doSomething(argument1, argument2, argument3, argument4 + , argument5); + +## Primitive Literals + +Strings should always use double quotes (never single quotes) and should always appear on a single line. Never use a slash to create a new line in a string. + + // Good + var name = "Nicholas"; + + // Bad: Single quotes + var name = 'Nicholas'; + + // Bad: Wrapping to second line + var longString = "Here's the story, of a man \ + named Brady."; + +Numbers should be written as decimal integers, e-notation integers, hexadecimal integers or floating-point decimals with at least one digit before and one digit after the decimal point. Never use octal literals. + + // Good + var count = 10; + + // Good + var price = 10.0; + var price = 10.00; + + // Good + var num = 0xA2; + + // Good + var num = 1e23; + + // Bad: Hanging decimal point + var price = 10.; + + // Bad: Leading decimal point + var price = .1; + + // Bad: Octal (base 8) is deprecated + var num = 010; + +The special value `null` should be used only in the following situations: + +1. To initialize a variable that may later be assign an object value. +1. To compare against an initialized variable that may or may not have an object value. +1. To pass into a function where an object is expected. +1. To return from a function where an object is expected. + +Examples: + + // Good + var person = null; + + // Good + function getPerson() { + if (condition) { + return new Person("Nicholas"); + } else { + return null; + } + } + + // Good + var person = getPerson(); + if (person !== null){ + doSomething(); + } + + // Bad: Testing against uninitialized variable + var person; + if (person != null){ + doSomething(); + } + + // Bad: Testing to see if an argument was passed + function doSomething(arg1, arg2, arg3, arg4){ + if (arg4 != null){ + doSomethingElse(); + } + } + +Never use the special value `undefined`. To see if a variable has been defined, use the `typeof` operator: + + // Good + if (typeof variable == "undefined") { + // do something + } + + // Bad: Using undefined literal + if (variable == undefined) { + // do something + } + +## Operator Spacing + +Operators with two operands must be preceded and followed by a single space to make the expression clear. Operators include assignments and logical operators. + + // Good + var found = (values[i] === item); + + // Good + if (found && (count > 10)) { + doSomething(); + } + + // Good + for (i = 0; i < count; i++) { + process(i); + } + + // Bad: Missing spaces + var found = (values[i]===item); + + // Bad: Missing spaces + if (found&&(count>10)) { + doSomething(); + } + + // Bad: Missing spaces + for (i=0; i 10)) { + doSomething(); + } + + // Good + for (i = 0; i < count; i++) { + process(i); + } + + // Bad: Extra space after opening paren + var found = ( values[i] === item); + + // Bad: Extra space before closing paren + if (found && (count > 10) ) { + doSomething(); + } + + // Bad: Extra space around argument + for (i = 0; i < count; i++) { + process( i ); + } + +## Object Literals + +Object literals should have the following format: + +* The opening brace should be on the same line as the containing statement. +* Each property-value pair should be indented one level with the first property appearing on the next line after the opening brace. +* Each property-value pair should have an unquoted property name, followed by a colon (no space preceding it), followed by the value. +* If the value is a function, it should wrap under the property name and should have a blank line both before and after the function. +* Additional empty lines may be inserted to group related properties or otherwise improve readability. +* The closing brace should be on a separate line. + +Examples: + + // Good + var object = { + + key1: value1, + key2: value2, + + func: function() { + // do something + }, + + key3: value3 + }; + + // Bad: Improper indentation + var object = { + key1: value1, + key2: value2 + }; + + // Bad: Missing blank lines around function + var object = { + + key1: value1, + key2: value2, + func: function() { + // do something + }, + key3: value3 + }; + +When an object literal is passed to a function, the opening brace should be on the same line as if the value is a variable. All other formatting rules from above still apply. + + // Good + doSomething({ + key1: value1, + key2: value2 + }); + + // Bad: All on one line + doSomething({ key1: value1, key2: value2 }); + +## Comments + +Make frequent use of comments to aid others in understanding your code. Use comments when: + +* Code is difficult to understand. +* The code might be mistaken for an error. +* Browser-specific code is necessary but not obvious. +* Documentation generation is necessary for an object, method, or property (use appropriate documentation comments). + +### Single-Line Comments + +Single-line comments should be used to documentation one line of code or a group of related lines of code. A single-line comment may be used in three ways: + +1. On a separate line, describing the code beneath it. +1. At the end of a line, describing the code before it. +1. On multiple lines, to comment out sections of code. + +When on a separate line, a single-line comment should be at the same indentation level as the code it describes and be preceded by a single line. Never use multiple single-line comments on consecutive lines, use a multi-line comment instead. + + // Good + if (condition){ + + // if you made it here, then all security checks passed + allowed(); + } + + // Bad: No empty line preceding comment + if (condition){ + // if you made it here, then all security checks passed + allowed(); + } + + // Bad: Wrong indentation + if (condition){ + + // if you made it here, then all security checks passed + allowed(); + } + + // Bad: This should be a multi-line comment + // This next piece of code is quite difficult, so let me explain. + // What you want to do is determine if the condition is true + // and only then allow the user in. The condition is calculated + // from several different functions and may change during the + // lifetime of the session. + if (condition){ + // if you made it here, then all security checks passed + allowed(); + } + +For single-line comments at the end of a line, ensure there is at least one indentation level between the end of the code and the beginning of the comment: + + // Good + var result = something + somethingElse; // somethingElse will never be null + + // Bad: Not enough space between code and comment + var result = something + somethingElse;// somethingElse will never be null + +The only acceptable time to have multiple single-line comments on successive lines is to comment out large sections of code. Multi-line comments should not be used for this purpose. + + // Good + // if (condition){ + // doSomething(); + // thenDoSomethingElse(); + // } + +### Multi-Line Comments + +Multi-line comments should be used to document code that requires more explanation. Each multi-line comment should have at least three lines: + +1. The first line contains only the `/*` comment opening. No further text is allowed on this line. +1. The next line(s) have a `*` aligned with the `*` in the first line. Text is allowed on these lines. +1. The last line has the `*/` comment opening aligned with the preceding lines. No other text is allowed on this line. + +The first line of multi-comments should be indented to the same level as the code it describes. Each subsequent line should have the same indentation plus one space (for proper alignment of the `*` characters). Each multi-line comment should be preceded by one empty line. + + // Good + if (condition){ + + /* + * if you made it here, + * then all security checks passed + */ + allowed(); + } + + // Bad: No empty line preceding comment + if (condition){ + /* + * if you made it here, + * then all security checks passed + */ + allowed(); + } + + // Bad: Missing a space after asterisk + if (condition){ + + /* + *if you made it here, + *then all security checks passed + */ + allowed(); + } + + // Bad: Wrong indentation + if (condition){ + + /* + * if you made it here, + * then all security checks passed + */ + allowed(); + } + + // Bad: Don't use multi-line comments for trailing comments + var result = something + somethingElse; /*somethingElse will never be null*/ + +### Comment Annotations + +Comments may be used to annotate pieces of code with additional information. These annotations take the form of a single word followed by a colon. The acceptable annotations are: + +* `TODO` - indicates that the code is not yet complete. Information about the next steps should be included. +* `HACK` - indicates that the code is using a shortcut. Information about why the hack is being used should be included. This may also indicate that it would be nice to come up with a better way to solve the problem. +* `XXX` - indicates that the code is problematic and should be fixed as soon as possible. +* `FIXME` - indicates that the code is problematic and should be fixed soon. Less important than `XXX`. +* `REVIEW` - indicates that the code needs to be reviewed for potential changes. + +These annotations may be used with either single-line or multi-line comments and should follow the same formatting rules as the general comment type. Examples: + + // Good + // TODO: I'd like to find a way to make this faster + doSomething(); + + // Good + /* + * HACK: Have to do this for IE. I plan on revisiting in + * the future when I have more time. This probably should + * get replaced before v1.2. + */ + if (document.all) { + doSomething(); + } + + // Good + // REVIEW: Is there a better way to do this? + if (document.all) { + doSomething(); + } + + // Bad: Annotation spacing is incorrect + // TODO : I'd like to find a way to make this faster + doSomething(); + + // Bad: Comment should be at the same indentation as code + // REVIEW: Is there a better way to do this? + if (document.all) { + doSomething(); + } + + +## Variable Declarations + +All variables should be declared before they are used. Variable declarations should take place at the beginning of a function using a single `var` statement with one variable per line. All lines after the first should be indented one level so the variable names line up. Variables should be initialized when declared if applicable and the equals operator should be at a consistent indentation level. Initialized variables should come first followed by uninitialized variables. + + // Good + var count = 10, + name = "Nicholas", + found = false, + empty; + + // Bad: Improper initialization alignment + var count = 10, + name = "Nicholas", + found= false, + empty; + + // Bad: Incorrect indentation + var count = 10, + name = "Nicholas", + found = false, + empty; + + // Bad: Multiple declarations on one line + var count = 10, name = "Nicholas", + found = false, empty; + + // Bad: Uninitialized variables first + var empty, + count = 10, + name = "Nicholas", + found = false; + + // Bad: Multiple var statements + var count = 10, + name = "Nicholas"; + + var found = false, + empty; + +Always declare variables. Implied globals should not be used. + +## Function Declarations + +Functions should be declared before they are used. When a function is not a method (not attached to an object) it should be defined using function declaration format (not function expression format nor using the `Function` constructor). There should be no space between the function name and the opening parentheses. There should be one space between the closing parentheses and the right brace. The right brace should be on the same line as the `function` keyword. There should be no space after the opening parentheses or before the closing parentheses. Named arguments should have a space after the comma but not before it. The function body should be indented one level. + + // Good + function doSomething(arg1, arg2) { + return arg1 + arg2; + } + + // Bad: Improper spacing of first line + function doSomething (arg1, arg2){ + return arg1 + arg2; + } + + // Bad: Function expression + var doSomething = function(arg1, arg2) { + return arg1 + arg2; + }; + + // Bad: Left brace on wrong line + function doSomething(arg1, arg2) + { + return arg1 + arg2; + } + + // Bad: Using Function constructor + var doSomething = new Function("arg1", "arg2", "return arg1 + arg2"); + +Functions declared inside of other functions should be declared immediately after the `var` statement. + + // Good + function outer() { + + var count = 10, + name = "Nicholas", + found = false, + empty; + + function inner() { + // code + } + + // code that uses inner() + } + + // Bad: Inner function declared before variables + function outer() { + + function inner() { + // code + } + + var count = 10, + name = "Nicholas", + found = false, + empty; + + // code that uses inner() + } + +Anonymous functions may be used for assignment of object methods or as arguments to other functions. There should be no space between the `function` keyword and the opening parentheses. + + // Good + object.method = function() { + // code + }; + + // Bad: Incorrect spacing + object.method = function () { + // code + }; + +Immediately-invoked functions should surround the entire function call with parentheses. + + // Good + var value = (function() { + + // function body + + return { + message: "Hi" + } + }()); + + // Bad: No parentheses around function call + var value = function() { + + // function body + + return { + message: "Hi" + } + }(); + + // Bad: Improper parentheses placement + var value = (function() { + + // function body + + return { + message: "Hi" + } + })(); + +## Naming + +Care should be taken to name variables and functions properly. Names should be limited to alphanumeric characters and, in some cases, the underscore character. Do not use the dollar sign (`$`) or back slash (`\`) characters in any names. + +Variable names should be formatted in camel case with the first letter being lowercase and the first letter of each subsequent word being uppercase. The first word of a variable name should be a noun (not a verb) to avoid confusion with functions. Do not use underscore for variable names. + + // Good + var accountNumber = "8401-1"; + + // Bad: Begins with uppercase letter + var AccountNumber = "8401-1"; + + // Bad: Begins with verb + var getAccountNumber = "8401-1"; + + // Bad: Uses underscore + var account_number = "8401-1"; + +Function names should also be formatted using camel case. The first word of a function name should be a verb (not a noun) to avoid confusion with variables. Do not use underscore for function names. + + // Good + function doSomething() { + // code + } + + // Bad: Begins with uppercase letter + function DoSomething() { + // code + } + + // Bad: Begins with noun + function car() { + // code + } + + // Bad: Uses underscores + function do_something() { + // code + } + +Constructor functions, those functions used with the `new` operator to create new objects, should be formatted in camel case but must begin with an uppercase letter. Constructor function names should begin with a non-verb because `new` is the action of creating an object instance. + + // Good + function MyObject() { + // code + } + + // Bad: Begins with lowercase letter + function myObject() { + // code + } + + // Bad: Uses underscores + function My_Object() { + // code + } + + // Bad: Begins with verb + function getMyObject() { + // code + } + +Variables that act as constants (values that won't be changed) should be formatted using all uppercase letters with words separated by a single underscore. + + // Good + var TOTAL_COUNT = 10; + + // Bad: Camel case + var totalCount = 10; + + // Bad: Mixed case + var total_COUNT = 10; + +Object properties follow the same naming conventions as variables. Object methods follow the same naming conventions as functions. If a property or method is meant to be private, then it should be prefixed with an underscore character. + + // Good + var object = { + _count: 10, + + _getCount: function () { + return this._count; + } + }; + +## Strict Mode + +Strict mode should be used only inside of functions and never globally. + + // Bad: Global strict mode + "use strict"; + + function doSomething() { + // code + } + + // Good + function doSomething() { + "use strict"; + + // code + } + +If you want strict mode to apply to multiple functions without needing to write `"use strict"` multiple times, use immediate function invocation: + + // Good + (function() { + "use strict"; + + function doSomething() { + // code + } + + function doSomethingElse() { + // code + } + + }()); + +## Assignments + +When assigning a value to a variable, use parentheses around a right-side expression that contains a comparison. + + // Good + var flag = (i < count); + + // Bad: Missing parentheses + var flag = i < count; + +## Equality Operators + +Use `===` and `!==` instead of `==` and `!=`. This avoids type coercion errors. + + // Good + var same = (a === b); + + // Bad: Using == + var same = (a == b); + +## Tenary Operator + +The ternary operator should be used only for assigning values conditionally and never as a shortcut for an `if` statement. + + // Good + var value = condition ? value1 : value2; + + // Bad: no assignment, should be an if statement + condition ? doSomething() : doSomethingElse(); + +## Statements + +### Simple Statements + +Each line should contain at most one statement. All simple statements should end with a semicolon (`;`). + + // Good + count++; + a = b; + + // Bad: Multiple statements on one line + count++; a = b; + +### return Statement + +A return statement with a value should not use parentheses unless they make the return value more obvious in some way. Example: + + return; + + return collection.size(); + + return (size > 0 ? size : defaultSize); + +### Compound Statements + +Compound statements are lists of statements enclosed inside of braces. + +* The enclosed statements should be indented one more level than the compound statement. +* The opening brace should be at the end of the line that begins the compound statement; the closing brace should begin a line and be indented to the beginning of the compound statement. +* Braces are used around all statements, even single statements, when they are part of a control structure, such as a `if` or `for` statement. This makes it easier to add statements without accidentally introducing bugs due to forgetting to add braces. +* The statement beginning keyword, such as `if`, should be followed by one space and the opening brace should be preceded by a space. + +### if Statement + +The `if` class of statements should have the following form: + + if (condition) { + statements + } + + if (condition) { + statements + } else { + statements + } + + if (condition) { + statements + } else if (condition) { + statements + } else { + statements + } + +It is never permissible to omit the braces in any part of an `if` statement. + + // Good + if (condition) { + doSomething(); + } + + // Bad: Improper spacing + if(condition){ + doSomething(); + } + + // Bad: Missing braces + if (condition) + doSomething(); + + // Bad: All on one line + if (condition) { doSomething(); } + + // Bad: All on one line without braces + if (condition) doSomething(); + +### for Statement + +The `for` class of statements should have the following form: + + for (initialization; condition; update) { + statements + } + + for (variable in object) { + statements + } + +Variables should not be declared in the initialization section of a `for` statement. + + // Good + var i, + len; + + for (i=0, len=10; i < len; i++) { + // code + } + + // Bad: Variables declared during initialization + for (var i=0, len=10; i < len; i++) { + // code + } + + // Bad: Variables declared during initialization + for (var prop in object) { + // code + } + +When using a `for-in` statement, double-check whether or not you need to use `hasOwnProperty()` to filter out object members. + +### while Statement + +The `while` class of statements should have the following form: + + while (condition) { + statements + } + +### do Statement + +The `do` class of statements should have the following form: + + do { + statements + } while (condition); + +Note the use of a semicolon as the final part of this statement. There should be a space before and after the `while` keyword. + +### switch Statement + +The `switch` class of statements should have the following form: + + switch (expression) { + case expression: + statements + + default: + statements + } + +Each `case` is indented one level under the `switch`. Each `case` after the first, including `default`, should be preceded by a single empty line. + +Each group of statements (except the default) should end with `break`, `return`, `throw`, or a comment indicating fall through. + + // Good + switch (value) { + case 1: + /* falls through */ + + case 2: + doSomething(); + break; + + case 3: + return true; + + default: + throw new Error("This shouldn't happen.); + } + +If a `switch` doesn't have a `default` case, then it should be indicated with a comment. + + // Good + switch (value) { + case 1: + /*falls through*/ + + case 2: + doSomething(); + break; + + case 3: + return true; + + // no default + } + +### try Statement + +The `try` class of statements should have the following form: + + try { + statements + } catch (variable) { + statements + } + + try { + statements + } catch (variable) { + statements + } finally { + statements + } + +## White Space + +Blank lines improve readability by setting off sections of code that are logically related. + +Two blank lines should always be used in the following circumstances: + +* Between sections of a source file +* Between class and interface definitions + +One blank line should always be used in the following circumstances: + +* Between methods +* Between the local variables in a method and its first statement +* Before a multi-line or single-line comment +* Between logical sections inside a method to improve readability + +Blank spaces should be used in the following circumstances: + +* A keyword followed by a parenthesis should be separated by a space. +* A blank space should appear after commas in argument lists. +* All binary operators except dot (`.`) should be separated from their operands by spaces. Blank spaces should never separate unary operators such as unary minus, increment (`++`), and decrement (`--`) from their operands. +* The expressions in a `for` statement should be separated by blank spaces. + +## Things to Avoid + +* Never use the primitive wrapper types, such as `String`, to create new objects. +* Never use `eval()`. +* Never use the `with` statement. This statement isn't available in strict mode and likely won't be available in future ECMAScript editions. diff --git a/docs/Command-line-interface.md b/docs/Command-line-interface.md new file mode 100644 index 000000000000..98b101c7f3b0 --- /dev/null +++ b/docs/Command-line-interface.md @@ -0,0 +1,79 @@ +To run ESLint on Node.js, you must have npm installed. If npm is not installed, follow the instructions here: http://npmjs.org/ + +Once npm is installed, run the following + + npm install -g eslint + +This installs the ESLint CLI from the npm repository. To run ESLint, use the following format: + + eslint [options] [file|dir]* + +Such as: + + eslint file1.js file2.js + +## Options + +The command line utility has several options. You can view the options by running `eslint -h`. + +``` +eslint [options] file.js [file.js] [dir] + +Options: + -h, --help Show help. + -c, --config Load configuration data from this file. + --rulesdir Load additional rules from this directory. + -f, --format Use a specific output format. [default: "compact"] +``` + +### -h, --help + +This option outputs the help menu, displaying all of the available options. All other flags are ignored when this is present. + +### -c, --config + +This option allows you to specify an alternate configuration file for ESLint (see below for more on configuration files). By default, it uses `conf/eslint.json`. + +Example: + + eslint -c ~/my-eslint.json file.js + +This example uses the configuration file at `~/my-eslint.json` instead of the default. + +### -f, --format + +This options specifies the output format for the console. At the moment, there is only `compact`, but more will be added soon. + +Example: + + eslint -f compact file.js + +When specified, the given format is output to the console. If you'd like to save that output into a file, you can do so on the command line like so: + + eslint -f compact file.js > results.txt + +This saves the output into the `results.txt` file. + +### --rulesdir + +This option allows you to specify a second directory from which to load rules files. This allows you to dynamically loading new rules at run time. This is useful when you have custom rules that aren't suitable for being bundled with ESLint. + +Example: + + eslint --rulesdir my-rules/ file.js + +The rules in your custom rules directory must following the same format as bundled rules to work properly. + +## Configuration Files + +You can turn specific rules on or off by creating your own configuration file. The configuration file is written in JSON and has a few top-level properties: + +* `rules` - this is an object where the keys are the rule IDs and the values are: + * 0 - turn the rule off + * 1 - turn the rule on as a warning (doesn't affect exit code) + * 2 - turn the rule on as a warning (exit code is 1) +* `env` - specify environmental information, such as: + * `nodejs` - set to true to indicate that the code being inspected is intended for use with NodeJS. ESLint will automatically add the appropriate references. + +(More options to be added soon.) + diff --git a/docs/Contributing.md b/docs/Contributing.md new file mode 100644 index 000000000000..5a25268ac191 --- /dev/null +++ b/docs/Contributing.md @@ -0,0 +1,39 @@ +One of the great things about open source projects is that anyone can contribute code. To help you in that process, there are several things that you should keep in mind. + +## Use Pull Requests + +If you want to submit code, please use a GitHub pull request. This is the fastest way for us to evaluate your code and to merge it into the code base. Please don't file an issue with snippets of code. Doing so means that we need to manually merge the changes in and update any appropriate tests. That decreases the likelihood that your code is going to get included in a timely manner. Please use pull requests. + +## Checklist + +We want to accept your contribution. Following these guidelines helps to create a patch that we want to accept: + +* Make sure there is an issue for any pull request you send. + * If an issue doesn't exist, create one *before* you submit the pull request. + * Issues should have full descriptions explaining the bug, enhancement, or request. +* The commit message should say "(fixes #1234)" at the of the description if it closes out an existing issue (replace 1234 with the issue number). +* The change should introduce no functional regression. Be sure to run `npm test` to verify your changes before submitting a pull request. +* Make separate pull requests for unrelated changes. Large pull requests with multiple unrelated changes may be closed without merging. +* A new feature must be accompanied by tests, this includes rules. +* All changes must work on the following Node.JS versions: + * 0.6.x + * 0.8.x + * 0.10.x +* Follow the [[Code Conventions]]. + +## New Rules + +Once you've written a rule, you can decide whether the rule is generic enough to be included in CSS Lint or if it's specific to your own use case. If you decide to submit your rule via a pull request, there are some things to keep in mind: + +1. Rules must be accompanied by unit tests. +1. In your pull request include: + 1. The use case for the rule - what is it trying to prevent or flag? + 1. Why you believe this rule is generic enough to be included in the main distribution + 1. Whether the rule should be on or off by default. + 1. Documentation for the rule (see [[no-console]] as an example). Put this documentation directly into the pull request. + +Keep in mind that not all rules will be accepted for the main distribution. You may also request that your rule by on by default but we may accept it as off by default. + +## Following Up + +All pull requests are sent through Travis CI to verify that no tests are broken. If the Travis build fails, it will show up on the pull request. We cannot accept any code that fails in Travis, so if this happens, make fixes and update the pull request to trigger another build. \ No newline at end of file diff --git a/docs/Developer-Guide.md b/docs/Developer-Guide.md new file mode 100644 index 000000000000..941586ae0a91 --- /dev/null +++ b/docs/Developer-Guide.md @@ -0,0 +1,33 @@ +This guide is intended for those who wish to: + +* Contribute code to ESLint +* Create their own rules for ESLint + +In order to work with ESLint as a developer, it's recommended that: + +* You know JavaScript, since ESLint is written in JavaScript. +* You have some familiarity with Node.js, since ESLint runs on it. +* You're comfortable with command-line programs. +* You understand unit tests and why they're important. + +If that sounds like you, then continue reading to get started. + +## Section 1: Get the [[Source Code]] + +Before you can get started, you'll need to get a copy of the ESLint source code. This section explains how to do that and a little about the source code structure. + +## Section 2: Setup a [[Development Environment]] + +Developing for ESLint is a bit different than running it on the command line. This section shows you how to setup a development environment and get you ready to write code. + +## Section 3: Run the [[Unit Tests]] + +There are a lot of unit tests included with ESLint to make sure that we're keeping on top of code quality. This section explains how to run the unit tests. + +## Section 4: [[Working with Rules]] + +You're finally ready to start working with rules. You may want to fix an existing rule or create a new one. This section explains how to do all of that. + +## Section 5: [[Contributing]] + +Once you've made changes that you want to share with the community, the next step is to submit those changes back via a pull request. \ No newline at end of file diff --git a/docs/Development-Environment.md b/docs/Development-Environment.md new file mode 100644 index 000000000000..82079d3c3426 --- /dev/null +++ b/docs/Development-Environment.md @@ -0,0 +1,36 @@ +ESLint has a very lightweight development environment that makes updating code fast and easy. If you've checked out the code already, then the next step is to make sure you have all of the required utilities. Node.js and npm are the two things you'll need. + +## Install Node.js + +Go to http://nodejs.org to download and install the latest stable version for your operating system. + +Most of the installers come with [npm](http://npmjs.org) already installed, but if for some reason it doesn't work on your system, you can install it manually using the instructions on the website. + +## Development Mode + +To run ESLint is dev mode you will need to first uninstall the real ESLint utility (if you had previously installed it from npm): + + npm remove -g eslint + +Next, go to the directory in which you've checked out the ESLint source code and run: + + npm link + +The global `eslint` will now point to the files in your development repository instead of a globally-installed version from npm. You can now use `eslint` directly to test your changes. + +If you ever update from the central repository and there are errors, it might be because you are missing some dependencies. If that happens, just run `npm link` again to get the latest dependencies. + +## Build Scripts + +ESLint has only one real build script you need to know about: `npm test`. By running `npm test`, you are verifying that all JSON files are free of syntax errors, running all tests, and checking the code coverage on those tests. + +Be sure to run `npm test` whenever you make changes to ensure that you've not broken anything that was previously working. + +## Workflow + +Whenever you make changes to the ESLint source files, you'll need to run `npm test` to rerun the tests. The workflow is: + +1. Make changes +1. Run `npm test` to run tests on the command line + +You'll have to do this each time you make a change. The tests are run automatically whenever a pull request is received, so make sure to verify your changes work before submitting them. \ No newline at end of file diff --git a/docs/Home.md b/docs/Home.md new file mode 100644 index 000000000000..bc82b2c4d26b --- /dev/null +++ b/docs/Home.md @@ -0,0 +1,19 @@ +## [[About]] + +Learn more about ESLint and why it came about and the general philosophy behind it. + +## [[Architecture]] + +Explains how the code is organized and why it is organized in that way. + +## [[Rules]] + +ESLint comes with some default rules to get you started. This is the complete list. + +## [[Command Line Interface]] + +ESLint is written to be used primarily for the command line. Learn about its usage here. + +## [[Developer Guide]] + +The developer guide contains information for ESLint developers. If you want to contribute to the project, or even just tinker on your own, this guide explains how to get the source and work with it. \ No newline at end of file diff --git a/docs/No-debugger.md b/docs/No-debugger.md new file mode 100644 index 000000000000..a55ea9fb508f --- /dev/null +++ b/docs/No-debugger.md @@ -0,0 +1,17 @@ +The `debugger` statement is used to tell the executing JavaScript environment to stop execution and start up a debugger at the current point in the code. This has fallen out of favor as a good practice with the advent of modern debugging and development tools. Production code should definitely not contain `debugger`, as it will cause the browser to stop executing code and open an appropriate debugger. + +```js +debugger; +``` + +## Rule Details + +This rule is aimed at eliminating `debugger` references from your JavaScript. As such, it warns whenever it sees `debugger` used as an identifier in code. + +## When Not To Use It + +If your code is still very much in development and don't want to worry about stripping about `debugger` statements, then turn this rule off. You'll generally want to turn it back on when testing code prior to deployment. + +## Further Reading + +* [Debugger](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger) diff --git a/docs/No-empty.md b/docs/No-empty.md new file mode 100644 index 000000000000..9f5b58dcb67b --- /dev/null +++ b/docs/No-empty.md @@ -0,0 +1,25 @@ +Empty statements usually occur due to refactoring that wasn't completed. You may end up with empty statements inside of blocks or `switch`, or by having too many semicolons in a row. + +## Rule Details + +This rule is aimed at eliminating empty statements. While not technically an error, empty statements can be a source of confusion when reading code. + +The following patterns are considered warnings: + +```js +if (foo) { +} + +while (foo) { +} + +foo();; + +switch(foo) { +} +``` + +## When Not To Use It + +If you intentionally use empty statements then you can disable this rule. + diff --git a/docs/No-unreachable.md b/docs/No-unreachable.md new file mode 100644 index 000000000000..f96425f4bd99 --- /dev/null +++ b/docs/No-unreachable.md @@ -0,0 +1,13 @@ +A number of statements unconditionally exit a block of code. Any statements after that will not be executed and may be an error. The presence of unreachable code is usually a sign of a coding error. + +```js +function fn() { + x = 1; + return x; + x = 3; // this will never execute +} +``` + +## Rule Details + +This rule is aimed at detecting unreachable code. It produces an error when a statements in a block exist after a `return`, `throw`, `break`, or `continue` statement. The rule checks inside block statements and switch cases. diff --git a/docs/Quote-props.md b/docs/Quote-props.md new file mode 100644 index 000000000000..c67e37a25713 --- /dev/null +++ b/docs/Quote-props.md @@ -0,0 +1,78 @@ +Similar to how quoting attribute values in HTML is a good idea, quoting property names in JavaScript is good practice. + +Ensuring property names in object literals are always wrapped in quotes is generally a good idea, since [depending on the property name you may need to quote them anyway](http://mathiasbynens.be/notes/javascript-properties). Consider this example: + +```js +var object = { + foo: "bar", + baz: 42, + "qux-lorem": true +}; +``` + +Here, the properties `foo` and `baz` are not wrapped in quotes, but `qux-lorem` is, because it doesn’t work without the quotes. This is rather inconsistent. Instead, you may prefer to quote property names consistently: + +```js +var object = { + "foo": "bar", + "baz": 42, + "qux-lorem": true +}; +``` + +…or, if you prefer single quotes: + +```js +var object = { + 'foo': 'bar', + 'baz': 42, + 'qux-lorem': true +}; +``` + +Much better, no? If that didn’t convince you, here’s another example: + +```js +var object = { + 1e2: 1, + 100: 2 +}; +``` + +This may look alright on first sight, but this code in fact throws a syntax error in strict mode. This happens because `1e2` and `100` are coerced into strings before getting used as the property name. Both `String(1e2)` and `String(100)` happen to be equal to `"100"`, which causes the “Duplicate data property in object literal not allowed in strict mode” error. Issues like that can be tricky to debug. Yet, they can easily be avoided, by simply always quoting property names in object literals. + +## Rule Details + +This rule helps you enforce consistent quoting of property names. + +The following patterns are considered warnings: + +```js +var object = { + foo: "bar", + baz: 42, + "qux-lorem": true +}; +``` + +The following patterns are considered okay and do not cause warnings: + +```js +var object = { + "foo": "bar", + "baz": 42, + "qux-lorem": true +}; +``` + +```js +var object = { + 'foo': 'bar', + 'baz': 42, + 'qux-lorem': true +}; +``` + +## When Not To Use It + +If you don’t care if property names are consistently wrapped in quotes or not, turn this rule off. diff --git a/docs/Rules.md b/docs/Rules.md new file mode 100644 index 000000000000..6ac11700ec19 --- /dev/null +++ b/docs/Rules.md @@ -0,0 +1,40 @@ +Rules in ESLint are divided into several categories to help you better understand their value. Additionally, not all rules are enabled by default. Those that are not enabled by default are marked as being off. + +## Possible Errors + +The following rules point out areas where you might have made mistakes. + +* [[no-console]] - disallow use of `console` +* [[no-debugger]] - disallow use of `debugger` +* [[no-empty]] - disallow empty statements +* [[no-unreachable]] - disallow unreachable statements after a return, throw, continue, or break statement +* [[use-isnan]] - disallow comparisons with the value `NaN` + +## Best Practices + +These are rules designed to prevent you from making mistakes. They either prescribe a better way of doing something or help you avoid footguns. + +* [[no-caller]] - disallow use of `arguments.caller` or `arguments.callee` are used +* [[curly]] - require curly brace for all control statements +* [[eqeqeq]] - require the use of `===` and `!==` +* [[no-eval]] - disallow use of `eval()` +* [[no-with]] - disallow use of the `with` statement +* [[no-undef-init]] - disallow use of undefined when initializing variables +* [[no-floating-decimal]] - disallow the use of leading or trailing decimal points in numeric literals +* [[no-octal]] - disallow use of octal literals + +## Stylistic Issues + +These rules are purely matters of style and are quite subjective. + +* [[camelcase]] - require camel case names +* [[new-cap]] - require a capital letter for constructors +* [[quote-props]] - require quotes around object literal property names +* [[semi]] - require use of semicolons instead of relying on ASI + +## Legacy + +The following rules are included for compatibility with [JSHint](http://jshint.com) and [JSLint](http://jslint.com). While the names of the rules may not match up with the JSHint/JSLint counterpart, the functionality is the same. + +* [[no-bitwise]] (off by default) - disallow use of bitwise operators +* [[guard-for-in]] (off by default) - make sure `for-in` loops have an `if` statement diff --git a/docs/Source-Code.md b/docs/Source-Code.md new file mode 100644 index 000000000000..103309274ba7 --- /dev/null +++ b/docs/Source-Code.md @@ -0,0 +1,37 @@ +ESLint is hosted at [GitHub](http://www.github.com) and uses [Git](http://git-scm.com/) for source control. In order to obtain the source code, you must first install Git on your system. Instructions for installing and setting up Git can be found at http://help.github.com/set-up-git-redirect. + +If you simply want to create a local copy of the source to play with, you can clone the main repository using this command: + + git clone git://github.com/nzakas/eslint.git + +If you're planning on contributing to ESLint, then it's a good idea to fork the repository. You can find instructions for forking a repository at http://help.github.com/fork-a-repo/. After forking the ESLintrepository, you'll want to create a local copy of your fork. + +## Start Developing + +Before you can get started developing, you'll need to have a couple of things installed: + +* [Node.JS](http://nodejs.org) +* [npm](http://npmjs.org) + +Once you have a local copy and have Node.JS and npm installed, you'll need to create a development link: + + cd eslint + npm link + +Now when you run `eslint`, it will be running your local copy and showing your changes. + +**Note:** It's a good idea to re-rerun `npm link` whenever you pull from the main repository to ensure you have the latest development dependencies. + +## Directory structure + +The ESLint directory and file structure is as follows: + +* `bin` - executable files that are available when ESLint is installed +* `config` - default configuration information +* `lib` - contains the source code + * `formatters` - all source files defining formatters + * `rules` - all source files defining rules +* `tests` - the main unit test folder + * `lib` - tests for the source code + * `reporters` - tests for the reporters + * `rules` - tests for the rules \ No newline at end of file diff --git a/docs/Unit-Tests.md b/docs/Unit-Tests.md new file mode 100644 index 000000000000..ce583b991c4f --- /dev/null +++ b/docs/Unit-Tests.md @@ -0,0 +1,7 @@ +Most parts of ESLint have unit tests associated with them. Unit tests are written using [Vows](http://vowsjs.org) and are required when making contributions to ESLint. You'll find all of the unit tests in the `tests` directory. + +When you first get the source code, you need to run `npm link` once initially to set ESLint for development. Once you've done that, you can run the tests via: + + npm test + +This automatically starts Vows and runs all tests in the `tests` directory. You need only add yours and it will automatically be picked up when running tests. \ No newline at end of file diff --git a/docs/Working-with-Rules.md b/docs/Working-with-Rules.md new file mode 100644 index 000000000000..1631ee33a249 --- /dev/null +++ b/docs/Working-with-Rules.md @@ -0,0 +1,152 @@ +Each ESLint rule has two files: a source file in the `lib/rules` directory and a test file in the `tests/lib/rules` directory. Both files should be named with the rule ID (i.e., `no-eval.js` for rule ID `no-eval`) The basic source code format for a rule is: + +```js +/** + * @fileoverview Rule to flag use of an empty block statement + * @author Nicholas C. Zakas + */ + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + return { + // properties go here + }; + +}; +``` + +**Important:** Rule submissions will not be accepted unless they are in this format. + +Each rule is represented by a single object with several properties. The properties are equivalent to AST node types from [SpiderMonkey](https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API). For example, if your rule wants to know when an identifier is found in the AST, then add a method called "Identifier", such as: + +```js +module.exports = function(context) { + + return { + + "Identifier": function(node) { + // do something with node + } + }; + +}; +``` + +Each method that matches a node in the AST will be passed the corresponding node. You can then evaluate the node and it's surrounding tree to determine whether or not an issue needs reporting. + +The main method you'll use is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts two arguments: the AST node that caused the report and a message to display. For example: + + context.report(node, "This is unexpected!"); + +The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node. + +### Getting the Source + +If your rule needs to get the actual JavaScript source to work with, then use the `context.getSource()` method. This method works as follows: + +```js + +// get all source +var source = context.getSource(); + +// get source for just this AST node +var nodeSource = context.getSource(node); + +// get source for AST node plus previous two characters +var nodeSourceWithPrev = context.getSource(node, 2); + +// get source for AST node plus following two characters +var nodeSourceWithFollowing = context.getSource(node, 0, 2); +``` + +In this way, you can look for patterns in the JavaScript text itself when the AST isn't providing the appropriate data (such as location of commas, semicolons, parentheses, etc.). + +## Rule Unit Tests + +Each rule must have a set of unit tests submitted with it to be accepted. The test file is named the same as the source file but lives in `tests/lib/`. For example, if your rule source file is `lib/rules/foo.js` then your test file should be `tests/lib/rules/foo.js`. + +For your rule, be sure to test: + +1. All instances that should be flagged as warnings. +1. At least one pattern that should **not** be flagged as a warning. + +The basic pattern for a rule unit test file is: + +```js +/** + * @fileoverview Tests for no-with rule. + * @author Nicholas C. Zakas + */ + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var vows = require("vows"), + assert = require("assert"), + eslint = require("../../../lib/eslint"); + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +var RULE_ID = "no-with"; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +vows.describe(RULE_ID).addBatch({ + + "when evaluating ''": { + + topic: "", + + "should report a violation": function(topic) { + var config = { rules: {} }; + config.rules[RULE_ID] = 1; + + var messages = eslint.verify(topic, config); + + assert.equal(messages.length, 1); + assert.equal(messages[0].ruleId, RULE_ID); + assert.equal(messages[0].message, ""); + assert.include(messages[0].node.type, ""); + } + }, + + "when evaluating ''": { + + topic: "", + + "should not report a violation": function(topic) { + var config = { rules: {} }; + config.rules[RULE_ID] = 1; + + var messages = eslint.verify(topic, config); + + assert.equal(messages.length, 0); + } + } + +}).export(module); +``` + +Be sure to replace the value of `RULE_ID` with your rule's ID. Also, replace `` and `` with some appropriate code strings to test. There are plenty of examples in the `tests/lib/rules/` directory. + +You should always check the number of messages as your first assert. This ensures that there aren't any more or less messages than you're expecting. Assuming there are no syntax errors, only your rule will produce messages. The second step is to ensure the type of message is correct. All rules output warnings, so check that this true for each message. Lastly, test the actual message text to ensure it's delivering the correct message to the user. You may also want to test if the returned AST node is the correct one. + +Provide as many unit tests as possible. Your pull request will never be turned down for having too many tests submitted with it! + +## Rule Naming Conventions + +The rule naming conventions for ESLint are fairly simple: + +* If your rule is disallowing something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`. +* If your rule is enforcing the inclusion of something, use a short name without a special prefix. +* Keep your rule names as short as possible, use abbreviations where appropriate, and no more than four words. +* Use dashes between words. \ No newline at end of file diff --git a/docs/new-cap.md b/docs/new-cap.md new file mode 100644 index 000000000000..779d2530bf74 --- /dev/null +++ b/docs/new-cap.md @@ -0,0 +1,25 @@ +The `new` operator in JavaScript creates a new instance of a particular type of object. That type of object is represented by a constructor function. Since constructor functions are just regular functions, the only defining characteristic is that `new` is being used as part of the call. Native JavaScript functions begin with an uppercase letter to distinguish those functions that are to be used as constructors from functions that are not. Many style guides recommend following this pattern to more easily determine which functions are to e used as constructors. + +```js +var friend = new Person(); +``` + +## Rule Details + +This rule is aimed at helping to distinguish regular functions from constructor functions. As such, it warns whenever it sees `new` followed by an identifier that isn't capitalized. + +The following patterns are considered warnings: + +```js +var friend = new person(); +``` + +The following patterns are considered okay and do not cause warnings: + +```js +var friend = new Person(); +``` + +## When Not To Use It + +If you have conventions that don't require an uppercase letter for constructors, turn this rule off. diff --git a/docs/no-arg.md b/docs/no-arg.md new file mode 100644 index 000000000000..250d6f539f3c --- /dev/null +++ b/docs/no-arg.md @@ -0,0 +1,34 @@ +Both `arguments.caller` and `arguments.callee` have fallen out of favor due to their negative performance and security implications. Both are forbidden from use in ECMAScript 5 strict mode and are likely to be deprecated in future versions of ECMAScript. In order to ensure future compatibility, it's recommended to avoid using both `arguments.caller` and `arguments.callee`. + +## Rule Details + +This rule is aimed at eliminating `arguments.caller` and `arguments.callee` from your JavaScript. As such, it warns whenever it sees either in code. + +The following patterns are considered warnings: + +```js +function findCallingFunction() { + return arguments.caller; +} + +function recurseInfinitely() { + return arguments.callee(); +} +``` + +The following patterns are considered okay and do not cause warnings: + +```js +// custom arguments +Arguments.callee(); +``` + +## When Not To Use It + +If you're using code that is meant strictly to run in an ECMAScript 3 environment, then you can safely disable this rule. Otherwise, it's recommended to use this rule all the time. + +## Further Reading + +* [Why was arguments.caller deprecated in JavaScript?](http://stackoverflow.com/questions/103598/why-was-the-arguments-callee-caller-property-deprecated-in-javascript) +* [arguments.callee](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments/callee) +* [arguments.caller](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments/caller) diff --git a/docs/no-console.md b/docs/no-console.md new file mode 100644 index 000000000000..234ae0ef8409 --- /dev/null +++ b/docs/no-console.md @@ -0,0 +1,33 @@ +In JavaScript that is designed to be executed in the browser, it's considered a best practice to avoid using methods on `console`. Such messages are considered to be for debugging purposes and therefore not suitable to ship to the client. In general, calls using `console` should be stripped before being pushed to production. + +```js +console.log("Made it here."); +console.error("That shouldn't have happened."); +``` + + +## Rule Details + +This rule is aimed at eliminating unwanted `console` references from your JavaScript. As such, it warns whenever it sees `console` used as an identifier in code. + +The following patterns are considered warnings: + +```js +console.log("Hello world!"); +console.error("Something bad happened."); +``` + +The following patterns are considered okay and do not cause warnings: + +```js +// custom console +Console.log("Hello world!"); +``` + +## When Not To Use It + +If you're using Node.js, however, `console` is used to output information to the user and so is not strictly used for debugging purposes. If you are developing for Node.js then you most likely do not want this rule enabled. + +## Further Reading + +* [Use Uglify to automatically strip debug messages from your JavaScript](http://jstarrdewar.com/blog/2013/02/28/use-uglify-to-automatically-strip-debug-messages-from-your-javascript) diff --git a/docs/use-isnan.md b/docs/use-isnan.md new file mode 100644 index 000000000000..61d8f1b64ea2 --- /dev/null +++ b/docs/use-isnan.md @@ -0,0 +1,5 @@ +In JavaScript, `NaN` is a special value of the `Number` type. It's used to represent any of the "not-a-number" values represented by the double-precision 64-bit format as specified by the IEEE Standard for Binary Floating-Point Arithmetic. `NaN` has the unique property of not being equal to anything, including itself. That is to say, that the condition `NaN !== NaN` evaluates to true. + +## Further reading + + - [Use the isNaN function to compare with NaN](http://jslinterrors.com/use-the-isnan-function-to-compare-with-nan/) \ No newline at end of file From dbf7499a492ad67c868b6509ad18405337d2624c Mon Sep 17 00:00:00 2001 From: Evan Goer Date: Mon, 15 Jul 2013 21:33:30 -0700 Subject: [PATCH 2/4] Add headings and correct internal links --- docs/About.md | 4 +++- docs/Architecture.md | 4 +++- docs/Code-Conventions.md | 4 +++- docs/Command-line-interface.md | 2 ++ docs/Contributing.md | 8 ++++--- docs/Developer-Guide.md | 14 +++++++----- docs/Development-Environment.md | 4 +++- docs/Home.md | 14 +++++++----- docs/No-debugger.md | 2 ++ docs/No-empty.md | 2 ++ docs/No-unreachable.md | 2 ++ docs/Quote-props.md | 2 ++ docs/Rules.md | 40 +++++++++++++++++---------------- docs/Source-Code.md | 4 +++- docs/Unit-Tests.md | 4 +++- docs/Working-with-Rules.md | 4 +++- docs/new-cap.md | 2 ++ docs/no-arg.md | 2 ++ docs/no-console.md | 2 ++ docs/use-isnan.md | 4 +++- 20 files changed, 82 insertions(+), 42 deletions(-) diff --git a/docs/About.md b/docs/About.md index 99e4725eac87..0f539dcd57d3 100644 --- a/docs/About.md +++ b/docs/About.md @@ -1,3 +1,5 @@ +# About + ESLint is an open source project originally created by Nicholas C. Zakas in June 2013. The goal of ESLint is to provide a pluggable linting utility for JavaScript. While [JSHint](http://jshint.com) and [JSLint](http://jslint.com) dominate JavaScript linting, neither one provides an API for plugging in your own rules. This means that if you need a new rule, you need to write it and get it accepted into the released product. That's lousy if you need to quickly add something to your build system or even if you need company-specific rules. ESLint is designed to have all rules completely pluggable. The default rules are written just like any plugin rules would be. They can all follow the same pattern, both for the rules themselves as well as tests. While ESLint will ship with some built-in rules for compatibility with JSHint and JSLint, you'll be able to dynamically load rules at any point in time. @@ -17,4 +19,4 @@ Additionally: * The only "error" that ships with ESLint is a parser error * Not all rules bundled with ESLint are enabled by default -* Bundled rules that are enabled are set as warnings (not errors) \ No newline at end of file +* Bundled rules that are enabled are set as warnings (not errors) diff --git a/docs/Architecture.md b/docs/Architecture.md index bbab7c12a7ef..76bd0544d027 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -1,3 +1,5 @@ +# Architecture + At a high level, there are a few key parts to ESLint: * `bin/eslint.js` - this is the file that actually gets executed with the command line utility. It's a dumb wrapper that does nothing more than bootstrap ESLint, passing the command line arguments to `cli`. This is intentionally small so as not to require heavy testing. @@ -12,4 +14,4 @@ TODO The main method of the `eslint` object is `verify()` and accepts two arguments: the source text to verify and a configuration object (the baked configuration of the given configuration file plus command line options). The method first parses the given text with Esprima and retrieves the AST. The AST is produced with both line/column and range locations which are useful for reporting location of issues and retrieving the source text related to an AST node, respectively. -Once the AST is available, `estraverse` is used to traverse the AST from top to bottom. At each node, the `eslint` object emits an event that has the same name as the node type (i.e., "Identifier", "WithStatement", etc.). On the way back up the subtree, an event is emitted with the AST type name and suffixed with ":after", such as "Identifier:after" - this allows rules to take action both on the way down and on the way up in the traversal. Each event is emitted with the appropriate AST node available. \ No newline at end of file +Once the AST is available, `estraverse` is used to traverse the AST from top to bottom. At each node, the `eslint` object emits an event that has the same name as the node type (i.e., "Identifier", "WithStatement", etc.). On the way back up the subtree, an event is emitted with the AST type name and suffixed with ":after", such as "Identifier:after" - this allows rules to take action both on the way down and on the way up in the traversal. Each event is emitted with the appropriate AST node available. diff --git a/docs/Code-Conventions.md b/docs/Code-Conventions.md index e24274e43f2b..3508552c2265 100644 --- a/docs/Code-Conventions.md +++ b/docs/Code-Conventions.md @@ -1,4 +1,6 @@ -Programming language style guides are important for the long-term maintainability of software. This guide is based on the [Code Conventions for the Java Programming Language](http:// java.sun.com/docs/codeconv/) and [Douglas Crockford's Code Conventions for the JavaScript Programming Language](http://javascript.crockford.com/code.html). Modifications have been made due to my personal experience and preferences. +# Code Conventions + +Programming language style guides are important for the long-term maintainability of software. This guide is based on the [Code Conventions for the Java Programming Language](http://java.sun.com/docs/codeconv/) and [Douglas Crockford's Code Conventions for the JavaScript Programming Language](http://javascript.crockford.com/code.html). Modifications have been made due to my personal experience and preferences. ## Indentation diff --git a/docs/Command-line-interface.md b/docs/Command-line-interface.md index 98b101c7f3b0..1015973441e1 100644 --- a/docs/Command-line-interface.md +++ b/docs/Command-line-interface.md @@ -1,3 +1,5 @@ +# Command line Interface + To run ESLint on Node.js, you must have npm installed. If npm is not installed, follow the instructions here: http://npmjs.org/ Once npm is installed, run the following diff --git a/docs/Contributing.md b/docs/Contributing.md index 5a25268ac191..7e99545b1730 100644 --- a/docs/Contributing.md +++ b/docs/Contributing.md @@ -1,3 +1,5 @@ +# Contributing + One of the great things about open source projects is that anyone can contribute code. To help you in that process, there are several things that you should keep in mind. ## Use Pull Requests @@ -19,7 +21,7 @@ We want to accept your contribution. Following these guidelines helps to create * 0.6.x * 0.8.x * 0.10.x -* Follow the [[Code Conventions]]. +* Follow the [Code Conventions](Code-Conventions.md). ## New Rules @@ -30,10 +32,10 @@ Once you've written a rule, you can decide whether the rule is generic enough to 1. The use case for the rule - what is it trying to prevent or flag? 1. Why you believe this rule is generic enough to be included in the main distribution 1. Whether the rule should be on or off by default. - 1. Documentation for the rule (see [[no-console]] as an example). Put this documentation directly into the pull request. + 1. Documentation for the rule (see [no-console](no-console.md) as an example). Put this documentation directly into the pull request. Keep in mind that not all rules will be accepted for the main distribution. You may also request that your rule by on by default but we may accept it as off by default. ## Following Up -All pull requests are sent through Travis CI to verify that no tests are broken. If the Travis build fails, it will show up on the pull request. We cannot accept any code that fails in Travis, so if this happens, make fixes and update the pull request to trigger another build. \ No newline at end of file +All pull requests are sent through Travis CI to verify that no tests are broken. If the Travis build fails, it will show up on the pull request. We cannot accept any code that fails in Travis, so if this happens, make fixes and update the pull request to trigger another build. diff --git a/docs/Developer-Guide.md b/docs/Developer-Guide.md index 941586ae0a91..00093416f5de 100644 --- a/docs/Developer-Guide.md +++ b/docs/Developer-Guide.md @@ -1,3 +1,5 @@ +# Developer Guide + This guide is intended for those who wish to: * Contribute code to ESLint @@ -12,22 +14,22 @@ In order to work with ESLint as a developer, it's recommended that: If that sounds like you, then continue reading to get started. -## Section 1: Get the [[Source Code]] +## Section 1: Get the [Source Code](Source-Code.md) Before you can get started, you'll need to get a copy of the ESLint source code. This section explains how to do that and a little about the source code structure. -## Section 2: Setup a [[Development Environment]] +## Section 2: Setup a [Development-Environment](Development-Environment.md) Developing for ESLint is a bit different than running it on the command line. This section shows you how to setup a development environment and get you ready to write code. -## Section 3: Run the [[Unit Tests]] +## Section 3: Run the [Unit Tests](Unit-Tests.md) There are a lot of unit tests included with ESLint to make sure that we're keeping on top of code quality. This section explains how to run the unit tests. -## Section 4: [[Working with Rules]] +## Section 4: [Working with Rules](Working-with-Rules.md) You're finally ready to start working with rules. You may want to fix an existing rule or create a new one. This section explains how to do all of that. -## Section 5: [[Contributing]] +## Section 5: [Contributing](Contributing.md) -Once you've made changes that you want to share with the community, the next step is to submit those changes back via a pull request. \ No newline at end of file +Once you've made changes that you want to share with the community, the next step is to submit those changes back via a pull request. diff --git a/docs/Development-Environment.md b/docs/Development-Environment.md index 82079d3c3426..3ec1b48f1e52 100644 --- a/docs/Development-Environment.md +++ b/docs/Development-Environment.md @@ -1,3 +1,5 @@ +# Development Environment + ESLint has a very lightweight development environment that makes updating code fast and easy. If you've checked out the code already, then the next step is to make sure you have all of the required utilities. Node.js and npm are the two things you'll need. ## Install Node.js @@ -33,4 +35,4 @@ Whenever you make changes to the ESLint source files, you'll need to run `npm te 1. Make changes 1. Run `npm test` to run tests on the command line -You'll have to do this each time you make a change. The tests are run automatically whenever a pull request is received, so make sure to verify your changes work before submitting them. \ No newline at end of file +You'll have to do this each time you make a change. The tests are run automatically whenever a pull request is received, so make sure to verify your changes work before submitting them. diff --git a/docs/Home.md b/docs/Home.md index bc82b2c4d26b..28831cda5999 100644 --- a/docs/Home.md +++ b/docs/Home.md @@ -1,19 +1,21 @@ -## [[About]] +# Home + +## [About](About.md) Learn more about ESLint and why it came about and the general philosophy behind it. -## [[Architecture]] +## [Architecture](Architecture.md) Explains how the code is organized and why it is organized in that way. -## [[Rules]] +## [Rules](Rules.md) ESLint comes with some default rules to get you started. This is the complete list. -## [[Command Line Interface]] +## [Command Line Interface](Command-line-interface.md) ESLint is written to be used primarily for the command line. Learn about its usage here. -## [[Developer Guide]] +## [Developer Guide](Developer-Guide.md) -The developer guide contains information for ESLint developers. If you want to contribute to the project, or even just tinker on your own, this guide explains how to get the source and work with it. \ No newline at end of file +The developer guide contains information for ESLint developers. If you want to contribute to the project, or even just tinker on your own, this guide explains how to get the source and work with it. diff --git a/docs/No-debugger.md b/docs/No-debugger.md index a55ea9fb508f..ebd703240152 100644 --- a/docs/No-debugger.md +++ b/docs/No-debugger.md @@ -1,3 +1,5 @@ +# No debugger + The `debugger` statement is used to tell the executing JavaScript environment to stop execution and start up a debugger at the current point in the code. This has fallen out of favor as a good practice with the advent of modern debugging and development tools. Production code should definitely not contain `debugger`, as it will cause the browser to stop executing code and open an appropriate debugger. ```js diff --git a/docs/No-empty.md b/docs/No-empty.md index 9f5b58dcb67b..3f4b6d9d7b6f 100644 --- a/docs/No-empty.md +++ b/docs/No-empty.md @@ -1,3 +1,5 @@ +# No empty + Empty statements usually occur due to refactoring that wasn't completed. You may end up with empty statements inside of blocks or `switch`, or by having too many semicolons in a row. ## Rule Details diff --git a/docs/No-unreachable.md b/docs/No-unreachable.md index f96425f4bd99..bdc877c485fd 100644 --- a/docs/No-unreachable.md +++ b/docs/No-unreachable.md @@ -1,3 +1,5 @@ +# No unreachable + A number of statements unconditionally exit a block of code. Any statements after that will not be executed and may be an error. The presence of unreachable code is usually a sign of a coding error. ```js diff --git a/docs/Quote-props.md b/docs/Quote-props.md index c67e37a25713..04c7722ea15c 100644 --- a/docs/Quote-props.md +++ b/docs/Quote-props.md @@ -1,3 +1,5 @@ +# Quote props + Similar to how quoting attribute values in HTML is a good idea, quoting property names in JavaScript is good practice. Ensuring property names in object literals are always wrapped in quotes is generally a good idea, since [depending on the property name you may need to quote them anyway](http://mathiasbynens.be/notes/javascript-properties). Consider this example: diff --git a/docs/Rules.md b/docs/Rules.md index 6ac11700ec19..b293d4f8e3d7 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -1,40 +1,42 @@ +# Rules + Rules in ESLint are divided into several categories to help you better understand their value. Additionally, not all rules are enabled by default. Those that are not enabled by default are marked as being off. ## Possible Errors The following rules point out areas where you might have made mistakes. -* [[no-console]] - disallow use of `console` -* [[no-debugger]] - disallow use of `debugger` -* [[no-empty]] - disallow empty statements -* [[no-unreachable]] - disallow unreachable statements after a return, throw, continue, or break statement -* [[use-isnan]] - disallow comparisons with the value `NaN` +* [no-console](no-console.md) - disallow use of `console` +* [no-debugger](No-debugger.md) - disallow use of `debugger` +* [no-empty](No-empty.md) - disallow empty statements +* [no-unreachable](No-unreachable.md) - disallow unreachable statements after a return, throw, continue, or break statement +* [use-isnan](use-isnan.md) - disallow comparisons with the value `NaN` ## Best Practices These are rules designed to prevent you from making mistakes. They either prescribe a better way of doing something or help you avoid footguns. -* [[no-caller]] - disallow use of `arguments.caller` or `arguments.callee` are used -* [[curly]] - require curly brace for all control statements -* [[eqeqeq]] - require the use of `===` and `!==` -* [[no-eval]] - disallow use of `eval()` -* [[no-with]] - disallow use of the `with` statement -* [[no-undef-init]] - disallow use of undefined when initializing variables -* [[no-floating-decimal]] - disallow the use of leading or trailing decimal points in numeric literals -* [[no-octal]] - disallow use of octal literals +* [no-caller] - disallow use of `arguments.caller` or `arguments.callee` are used +* [curly] - require curly brace for all control statements +* [eqeqeq] - require the use of `===` and `!==` +* [no-eval] - disallow use of `eval()` +* [no-with] - disallow use of the `with` statement +* [no-undef-init] - disallow use of undefined when initializing variables +* [no-floating-decimal] - disallow the use of leading or trailing decimal points in numeric literals +* [no-octal] - disallow use of octal literals ## Stylistic Issues These rules are purely matters of style and are quite subjective. -* [[camelcase]] - require camel case names -* [[new-cap]] - require a capital letter for constructors -* [[quote-props]] - require quotes around object literal property names -* [[semi]] - require use of semicolons instead of relying on ASI +* [camelcase] - require camel case names +* [new-cap](new-cap.md) - require a capital letter for constructors +* [quote-props](Quote-props.md) - require quotes around object literal property names +* [semi] - require use of semicolons instead of relying on ASI ## Legacy The following rules are included for compatibility with [JSHint](http://jshint.com) and [JSLint](http://jslint.com). While the names of the rules may not match up with the JSHint/JSLint counterpart, the functionality is the same. -* [[no-bitwise]] (off by default) - disallow use of bitwise operators -* [[guard-for-in]] (off by default) - make sure `for-in` loops have an `if` statement +* [no-bitwise] (off by default) - disallow use of bitwise operators +* [guard-for-in] (off by default) - make sure `for-in` loops have an `if` statement diff --git a/docs/Source-Code.md b/docs/Source-Code.md index 103309274ba7..df9d43b90495 100644 --- a/docs/Source-Code.md +++ b/docs/Source-Code.md @@ -1,3 +1,5 @@ +# Source Code + ESLint is hosted at [GitHub](http://www.github.com) and uses [Git](http://git-scm.com/) for source control. In order to obtain the source code, you must first install Git on your system. Instructions for installing and setting up Git can be found at http://help.github.com/set-up-git-redirect. If you simply want to create a local copy of the source to play with, you can clone the main repository using this command: @@ -34,4 +36,4 @@ The ESLint directory and file structure is as follows: * `tests` - the main unit test folder * `lib` - tests for the source code * `reporters` - tests for the reporters - * `rules` - tests for the rules \ No newline at end of file + * `rules` - tests for the rules diff --git a/docs/Unit-Tests.md b/docs/Unit-Tests.md index ce583b991c4f..ca3789f312fc 100644 --- a/docs/Unit-Tests.md +++ b/docs/Unit-Tests.md @@ -1,7 +1,9 @@ +# Unit Tests + Most parts of ESLint have unit tests associated with them. Unit tests are written using [Vows](http://vowsjs.org) and are required when making contributions to ESLint. You'll find all of the unit tests in the `tests` directory. When you first get the source code, you need to run `npm link` once initially to set ESLint for development. Once you've done that, you can run the tests via: npm test -This automatically starts Vows and runs all tests in the `tests` directory. You need only add yours and it will automatically be picked up when running tests. \ No newline at end of file +This automatically starts Vows and runs all tests in the `tests` directory. You need only add yours and it will automatically be picked up when running tests. diff --git a/docs/Working-with-Rules.md b/docs/Working-with-Rules.md index 1631ee33a249..a5f2e6a60c56 100644 --- a/docs/Working-with-Rules.md +++ b/docs/Working-with-Rules.md @@ -1,3 +1,5 @@ +# Working with Rules + Each ESLint rule has two files: a source file in the `lib/rules` directory and a test file in the `tests/lib/rules` directory. Both files should be named with the rule ID (i.e., `no-eval.js` for rule ID `no-eval`) The basic source code format for a rule is: ```js @@ -149,4 +151,4 @@ The rule naming conventions for ESLint are fairly simple: * If your rule is disallowing something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`. * If your rule is enforcing the inclusion of something, use a short name without a special prefix. * Keep your rule names as short as possible, use abbreviations where appropriate, and no more than four words. -* Use dashes between words. \ No newline at end of file +* Use dashes between words. diff --git a/docs/new-cap.md b/docs/new-cap.md index 779d2530bf74..af0d03969149 100644 --- a/docs/new-cap.md +++ b/docs/new-cap.md @@ -1,3 +1,5 @@ +# new cap + The `new` operator in JavaScript creates a new instance of a particular type of object. That type of object is represented by a constructor function. Since constructor functions are just regular functions, the only defining characteristic is that `new` is being used as part of the call. Native JavaScript functions begin with an uppercase letter to distinguish those functions that are to be used as constructors from functions that are not. Many style guides recommend following this pattern to more easily determine which functions are to e used as constructors. ```js diff --git a/docs/no-arg.md b/docs/no-arg.md index 250d6f539f3c..604c123fd100 100644 --- a/docs/no-arg.md +++ b/docs/no-arg.md @@ -1,3 +1,5 @@ +# no arg + Both `arguments.caller` and `arguments.callee` have fallen out of favor due to their negative performance and security implications. Both are forbidden from use in ECMAScript 5 strict mode and are likely to be deprecated in future versions of ECMAScript. In order to ensure future compatibility, it's recommended to avoid using both `arguments.caller` and `arguments.callee`. ## Rule Details diff --git a/docs/no-console.md b/docs/no-console.md index 234ae0ef8409..5422506f8c58 100644 --- a/docs/no-console.md +++ b/docs/no-console.md @@ -1,3 +1,5 @@ +# no console + In JavaScript that is designed to be executed in the browser, it's considered a best practice to avoid using methods on `console`. Such messages are considered to be for debugging purposes and therefore not suitable to ship to the client. In general, calls using `console` should be stripped before being pushed to production. ```js diff --git a/docs/use-isnan.md b/docs/use-isnan.md index 61d8f1b64ea2..e03c95e9d1c2 100644 --- a/docs/use-isnan.md +++ b/docs/use-isnan.md @@ -1,5 +1,7 @@ +# use isnan + In JavaScript, `NaN` is a special value of the `Number` type. It's used to represent any of the "not-a-number" values represented by the double-precision 64-bit format as specified by the IEEE Standard for Binary Floating-Point Arithmetic. `NaN` has the unique property of not being equal to anything, including itself. That is to say, that the condition `NaN !== NaN` evaluates to true. ## Further reading - - [Use the isNaN function to compare with NaN](http://jslinterrors.com/use-the-isnan-function-to-compare-with-nan/) \ No newline at end of file + - [Use the isNaN function to compare with NaN](http://jslinterrors.com/use-the-isnan-function-to-compare-with-nan/) From b8a2c70d5d011c4f606de5e5bb832290989abdee Mon Sep 17 00:00:00 2001 From: Evan Goer Date: Mon, 15 Jul 2013 21:37:59 -0700 Subject: [PATCH 3/4] Avoid accidentally creating a markdown link --- docs/Rules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Rules.md b/docs/Rules.md index b293d4f8e3d7..d5835a53b461 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -38,5 +38,5 @@ These rules are purely matters of style and are quite subjective. The following rules are included for compatibility with [JSHint](http://jshint.com) and [JSLint](http://jslint.com). While the names of the rules may not match up with the JSHint/JSLint counterpart, the functionality is the same. -* [no-bitwise] (off by default) - disallow use of bitwise operators -* [guard-for-in] (off by default) - make sure `for-in` loops have an `if` statement +* [no-bitwise] - disallow use of bitwise operators (off by default) +* [guard-for-in] - make sure `for-in` loops have an `if` statement (off by default) From 7731a8bfbe9eccb56bbd28b36e79c2bf044c50ba Mon Sep 17 00:00:00 2001 From: Evan Goer Date: Mon, 15 Jul 2013 21:38:28 -0700 Subject: [PATCH 4/4] Rename to create an 'index' file in GH web view --- docs/{Home.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{Home.md => README.md} (100%) diff --git a/docs/Home.md b/docs/README.md similarity index 100% rename from docs/Home.md rename to docs/README.md