Skip to content

Commit

Permalink
Merge pull request #20 from martinmacko47/with-statement
Browse files Browse the repository at this point in the history
#19 Add With control statement
  • Loading branch information
vkbansal committed Jun 13, 2017
2 parents dac709c + 0ecad40 commit 4a2c5c9
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 11 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -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 `<For>` (`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 `<For>` (`each` and `index` attributes) and `<With>`. 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).
Expand Down
20 changes: 16 additions & 4 deletions 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 `<For>` statements. Note that this includes no-undef's
exception built in for variables that are implicitly declared by `<For>` and `<With>` 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.

Expand All @@ -20,6 +20,12 @@ b = 10;
</For>
```

```js
<With foo={47}>
{bar}
</With>
```

The following patterns are not warnings:

```js
Expand All @@ -28,17 +34,23 @@ The following patterns are not warnings:
</For>
```

```js
<With foo={47}>
{foo}
</With>
```

## 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 <For> statements.
You'll only need this if you're using <For> or <With> statements.

## Compatibility

This rule is completely compatible with ESLint no-undef, except in the case of `<For>` statements.
This rule is completely compatible with ESLint no-undef, except in the case of `<For>` and `<With>` statements.

## Further Reading
- [ESLint no-undef documentation](http://eslint.org/docs/rules/no-undef)
3 changes: 2 additions & 1 deletion index.js
Expand Up @@ -9,7 +9,8 @@ module.exports = {
"For": true,
"When": true,
"Choose": true,
"Otherwise": true
"Otherwise": true,
"With": true
}
}
},
Expand Down
12 changes: 11 additions & 1 deletion lib/rules/jsx-jcs-no-undef.js
@@ -1,5 +1,5 @@
/**
* @fileoverview Extends generic eslint no-undef rule with custom logic for <For> statements.
* @fileoverview Extends generic eslint no-undef rule with custom logic for <For> and <With> statements.
* @author Alex Gilleran
*
* Version of https://github.com/eslint/eslint/blob/master/lib/rules/no-undef.js that filters out variables created
Expand Down Expand Up @@ -68,6 +68,16 @@ module.exports = function(context) {
return;
}
}

// If this ancestor is a <With> 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({
Expand Down
5 changes: 5 additions & 0 deletions lib/utils.js
Expand Up @@ -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);
Expand All @@ -60,4 +64,5 @@ exports.isForComponent = isForComponent;
exports.isIfComponent = isIfComponent;
exports.isChooseComponent = isChooseComponent;
exports.isWhenComponent = isWhenComponent;
exports.isWithComponent = isWithComponent;
exports.findAttr = findAttr;
128 changes: 124 additions & 4 deletions tests/lib/rules/jsx-jcs-no-undef.js
Expand Up @@ -18,6 +18,7 @@ var ruleTester = new RuleTester();

ruleTester.run("jsx-jcs-no-undef", rule, {
valid: [
// <For> statement
{
code:
'<For each="element" of={this.props.elements} index="idx">' +
Expand Down Expand Up @@ -62,6 +63,49 @@ ruleTester.run("jsx-jcs-no-undef", rule, {
}
},

// <With> statement
{
code:
'<With value={47}>' +
'{value}' +
'<div>' +
'{value}' +
'</div>' +
'</With>'
,
parserOptions: {
ecmaFeatures: {
jsx: true
}
}
}, {
code:
'<With value={47} anotherValue={"foo"}>' +
'<AnotherElement foo={value} bar={anotherValue}>' +
'<YetAnotherElement foo={value} bar={anotherValue} />' +
'</AnotherElement>' +
'</With>'
,
parserOptions: {
ecmaFeatures: {
jsx: true
}
}
}, {
code:
'<With value={47}>' +
'<With anotherValue={"foo"}>' +
'{value} {anotherValue}' +
'</With>' +
'</With>'
,
parserOptions: {
ecmaFeatures: {
jsx: true
}
}
},

// Standard no-undef rules follow:
"var a = 1, b = 2; a;",
"/*global b*/ function f() { b; }",
Expand Down Expand Up @@ -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}},

Expand Down Expand Up @@ -133,6 +177,7 @@ ruleTester.run("jsx-jcs-no-undef", rule, {
],

invalid: [
// <For> statement
{
code:
'<For each="element" of={this.props.elements} index="idx">' +
Expand Down Expand Up @@ -208,6 +253,81 @@ ruleTester.run("jsx-jcs-no-undef", rule, {
]
},

// <With> statement
{
code:
'<With value={47}>' +
'{wrongElement}' +
'</With>'
,
parserOptions: {
ecmaFeatures: {
jsx: true
}
},
errors: [{message: "'wrongElement' is not defined.", type: "Identifier"}]
},
{
code:
'<With value={47}>' +
'<Blah key={wrongElement}></Blah>' +
'</With>'
,
parserOptions: {
ecmaFeatures: {
jsx: true
}
},
errors: [{message: "'wrongElement' is not defined.", type: "Identifier"}]
},
{
code:
'<With value={47}>' +
'<WrapperElement>' +
'{wrongElement}' +
'</WrapperElement>' +
'</With>'
,
parserOptions: {
ecmaFeatures: {
jsx: true
}
},
errors: [{message: "'wrongElement' is not defined.", type: "Identifier"}]
},
{
code:
'<With value={47}>' +
'<WrapperElement>' +
'<Blah key={wrongElement}></Blah>' +
'</WrapperElement>' +
'</With>'
,
parserOptions: {
ecmaFeatures: {
jsx: true
}
},
errors: [{message: "'wrongElement' is not defined.", type: "Identifier"}]
}, {
code:
'<With value={47}>' +
'{anotherValue}' +
'<With anotherValue={this.props.elements}>' +
'{value}' +
'</With>' +
'</With>'
,
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"}]},
{
Expand All @@ -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},
Expand Down

0 comments on commit 4a2c5c9

Please sign in to comment.