diff --git a/README.md b/README.md index 288f012..e2e488e 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ The plugin comes with a number of rules and an environment that sets the control * [jsx-otherwise-once-last](docs/rules/jsx-otherwise-once-last.md): Warn when `Otherwise` tag is used more than once inside `Choose` and is not last child. * [jsx-use-if-tag](docs/rules/jsx-use-if-tag.md): Use `If` tag instead of ternary operator. * [jsx-when-require-condition](docs/rules/jsx-when-require-condition.md): Warn if `When` tag is missing `condition` attribute. -* [jsx-jcs-no-undef](docs/rules/jsx-jcs-no-undef.md): Replaces the built-in `no-undef` rule with one that is tolerant of variables expressed in `` (`each` and `index` attributes). Note that to stop getting errors from `no-undef` you have to turn it off and this on. +* [jsx-jcs-no-undef](docs/rules/jsx-jcs-no-undef.md): Replaces the built-in `no-undef` rule with one that is tolerant of variables expressed in `` (`each` and `index` attributes) and ``. Note that to stop getting errors from `no-undef` you have to turn it off and this on. ## Credits Thanks to @yannickcr for his awesome [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react). diff --git a/docs/rules/jsx-jcs-no-undef.md b/docs/rules/jsx-jcs-no-undef.md index 1abddc7..57aa29d 100644 --- a/docs/rules/jsx-jcs-no-undef.md +++ b/docs/rules/jsx-jcs-no-undef.md @@ -1,7 +1,7 @@ -# Disallow Undeclared Variables, While Treating Each and Index in For statements as declared (jsx-jcs-no-undef) +# Disallow Undeclared Variables, While Treating Each and Index in For and keys in With statements as declared (jsx-jcs-no-undef) This rule is the same as the generic eslint no-undef rule (see http://eslint.org/docs/rules/no-undef) except with an -exception built in for variables that are implicitly declared by `` statements. Note that this includes no-undef's +exception built in for variables that are implicitly declared by `` and `` statements. Note that this includes no-undef's code and completely replaces it rather than supplementing it - if this rule is on, no-undef should be off. It is compatible with no-undef's options and `/* global */` declarations. @@ -20,6 +20,12 @@ b = 10; ``` +```js + + {bar} + +``` + The following patterns are not warnings: ```js @@ -28,17 +34,23 @@ The following patterns are not warnings: ``` +```js + + {foo} + +``` + ## Options * `typeof` set to true will warn for variables used inside typeof check (Default false). ## When Not To Use It -You'll only need this if you're using statements. +You'll only need this if you're using or statements. ## Compatibility -This rule is completely compatible with ESLint no-undef, except in the case of `` statements. +This rule is completely compatible with ESLint no-undef, except in the case of `` and `` statements. ## Further Reading - [ESLint no-undef documentation](http://eslint.org/docs/rules/no-undef) diff --git a/index.js b/index.js index da0e1e1..316497d 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,8 @@ module.exports = { "For": true, "When": true, "Choose": true, - "Otherwise": true + "Otherwise": true, + "With": true } } }, diff --git a/lib/rules/jsx-jcs-no-undef.js b/lib/rules/jsx-jcs-no-undef.js index 6d85b13..0a85900 100644 --- a/lib/rules/jsx-jcs-no-undef.js +++ b/lib/rules/jsx-jcs-no-undef.js @@ -1,5 +1,5 @@ /** - * @fileoverview Extends generic eslint no-undef rule with custom logic for statements. + * @fileoverview Extends generic eslint no-undef rule with custom logic for and statements. * @author Alex Gilleran * * Version of https://github.com/eslint/eslint/blob/master/lib/rules/no-undef.js that filters out variables created @@ -68,6 +68,16 @@ module.exports = function(context) { return; } } + + // If this ancestor is a element... + if (thisElement.type === "JSXElement" && utils.isWithComponent(thisElement.openingElement)) { + var someAttr = thisElement.openingElement.attributes.some(function(attr) { + return attr.name.name === identifier.name; + }); + if (someAttr) { + return; + } + } } context.report({ diff --git a/lib/utils.js b/lib/utils.js index 0c6dce6..459b3fa 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -42,6 +42,10 @@ function isWhenComponent(child) { return isTag("When", child); } +function isWithComponent(node) { + return isTag("With", node); +} + function findAttr(attributes, name) { for (var i = 0, l = attributes.length; i < l; i++) { var attr = isAttr(attributes[i], name); @@ -60,4 +64,5 @@ exports.isForComponent = isForComponent; exports.isIfComponent = isIfComponent; exports.isChooseComponent = isChooseComponent; exports.isWhenComponent = isWhenComponent; +exports.isWithComponent = isWithComponent; exports.findAttr = findAttr; diff --git a/tests/lib/rules/jsx-jcs-no-undef.js b/tests/lib/rules/jsx-jcs-no-undef.js index f5ccde6..95f9d0e 100644 --- a/tests/lib/rules/jsx-jcs-no-undef.js +++ b/tests/lib/rules/jsx-jcs-no-undef.js @@ -18,6 +18,7 @@ var ruleTester = new RuleTester(); ruleTester.run("jsx-jcs-no-undef", rule, { valid: [ + // statement { code: '' + @@ -62,6 +63,49 @@ ruleTester.run("jsx-jcs-no-undef", rule, { } }, + // statement + { + code: + '' + + '{value}' + + '
' + + '{value}' + + '
' + + '
' + , + parserOptions: { + ecmaFeatures: { + jsx: true + } + } + }, { + code: + '' + + '' + + '' + + '' + + '' + , + parserOptions: { + ecmaFeatures: { + jsx: true + } + } + }, { + code: + '' + + '' + + '{value} {anotherValue}' + + '' + + '' + , + parserOptions: { + ecmaFeatures: { + jsx: true + } + } + }, + // Standard no-undef rules follow: "var a = 1, b = 2; a;", "/*global b*/ function f() { b; }", @@ -103,8 +147,8 @@ ruleTester.run("jsx-jcs-no-undef", rule, { parserOptions: {sourceType: "module"} }, {code: "var a; [a] = [0];", parserOptions: {ecmaVersion: 6}}, - {code: "var a; ({a}) = {};", parserOptions: {ecmaVersion: 6}}, - {code: "var a; ({b: a}) = {};", parserOptions: {ecmaVersion: 6}}, + {code: "var a; ({a} = {});", parserOptions: {ecmaVersion: 6}}, + {code: "var a; ({b: a} = {});", parserOptions: {ecmaVersion: 6}}, {code: "var obj; [obj.a, obj.b] = [0, 1];", parserOptions: {ecmaVersion: 6}}, {code: "URLSearchParams;", env: {browser: true}}, @@ -133,6 +177,7 @@ ruleTester.run("jsx-jcs-no-undef", rule, { ], invalid: [ + // statement { code: '' + @@ -208,6 +253,81 @@ ruleTester.run("jsx-jcs-no-undef", rule, { ] }, + // statement + { + code: + '' + + '{wrongElement}' + + '' + , + parserOptions: { + ecmaFeatures: { + jsx: true + } + }, + errors: [{message: "'wrongElement' is not defined.", type: "Identifier"}] + }, + { + code: + '' + + '' + + '' + , + parserOptions: { + ecmaFeatures: { + jsx: true + } + }, + errors: [{message: "'wrongElement' is not defined.", type: "Identifier"}] + }, + { + code: + '' + + '' + + '{wrongElement}' + + '' + + '' + , + parserOptions: { + ecmaFeatures: { + jsx: true + } + }, + errors: [{message: "'wrongElement' is not defined.", type: "Identifier"}] + }, + { + code: + '' + + '' + + '' + + '' + + '' + , + parserOptions: { + ecmaFeatures: { + jsx: true + } + }, + errors: [{message: "'wrongElement' is not defined.", type: "Identifier"}] + }, { + code: + '' + + '{anotherValue}' + + '' + + '{value}' + + '' + + '' + , + parserOptions: { + ecmaFeatures: { + jsx: true + } + }, + errors: [ + {message: "'anotherValue' is not defined.", type: "Identifier"} + ] + }, + // standard no-undef rules follow: {code: "a = 1;", errors: [{message: "'a' is not defined.", type: "Identifier"}]}, { @@ -230,8 +350,8 @@ ruleTester.run("jsx-jcs-no-undef", rule, { parserOptions: {ecmaVersion: 6, ecmaFeatures: {jsx: true}} }, {code: "[a] = [0];", parserOptions: {ecmaVersion: 6}, errors: [{message: "'a' is not defined."}]}, - {code: "({a}) = {};", parserOptions: {ecmaVersion: 6}, errors: [{message: "'a' is not defined."}]}, - {code: "({b: a}) = {};", parserOptions: {ecmaVersion: 6}, errors: [{message: "'a' is not defined."}]}, + {code: "({a} = {});", parserOptions: {ecmaVersion: 6}, errors: [{message: "'a' is not defined."}]}, + {code: "({b: a} = {});", parserOptions: {ecmaVersion: 6}, errors: [{message: "'a' is not defined."}]}, { code: "[obj.a, obj.b] = [0, 1];", parserOptions: {ecmaVersion: 6},