Skip to content

Commit e52f10a

Browse files
author
[Interfaced] Кирилл Дронкин
committed
1.2.0
1 parent d458e69 commit e52f10a

22 files changed

Lines changed: 341 additions & 70 deletions

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Change log
22

3+
## 1.2.0 (release date: 30.08.2018)
4+
5+
* New redefinitions:
6+
- `no-param-reassign` to ignore report for self assignment with typecast
7+
38
## 1.1.2 (release date: 2.08.2018)
49

510
* `lines-around-class`: handle nested classes

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ Some useful rules which are provided by ESLint are slightly inappropriate for Cl
6464
so we redefine them with some adjusting for our requirements.
6565

6666
* [interfaced/camelcase](docs/redefined/camelcase.md)
67+
* [interfaced/no-param-reassign](docs/redefined/no-param-reassign.md)
6768
* [interfaced/no-unused-expressions](docs/redefined/no-unused-expressions.md)
6869
* [interfaced/require-jsdoc](docs/redefined/require-jsdoc.md)
6970
* [interfaced/valid-jsdoc](docs/redefined/valid-jsdoc.md)

docs/redefined/camelcase.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ but doesn't when `interfaced/camelcase` is used.
1616

1717
* [Original](https://eslint.org/docs/rules/camelcase)
1818
* [Source](../../lib/rules/redefined/camelcase.js)
19-
* [Tests](../../test/eslint/rules/camelcase.js)
19+
* [Tests](../../test/eslint/rules/redefined/camelcase.js)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# interfaced/no-param-reassign
2+
3+
Ignore report for self assignment with typecast.
4+
5+
## Examples
6+
7+
The following code causes the reports for `arg` from original `no-param-reassign`:
8+
9+
```js
10+
function func(arg) {
11+
arg = /** @type {string} */ (arg);
12+
}
13+
```
14+
15+
and when `props` option is set to `true`:
16+
17+
```js
18+
function func(arg) {
19+
arg.a = /** @type {string} */ (arg.a);
20+
}
21+
```
22+
23+
but doesn't when `interfaced/no-param-reassign` is used.
24+
25+
## Resources
26+
27+
* [Original](https://eslint.org/docs/rules/no-param-reassign)
28+
* [Source](../../lib/rules/redefined/no-param-reassign.js)
29+
* [Tests](../../test/eslint/rules/redefined/no-param-reassign.js)

docs/redefined/no-unused-expressions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ but doesn't when `interfaced/no-unused-expressions` is used.
3030

3131
* [Original](https://eslint.org/docs/rules/no-unused-expressions)
3232
* [Source](../../lib/rules/redefined/no-unused-expressions.js)
33-
* [Tests](../../test/eslint/rules/no-unused-expressions.js)
33+
* [Tests](../../test/eslint/rules/redefined/no-unused-expressions.js)

docs/redefined/require-jsdoc.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ but does when `interfaced/require-jsdoc` is used.
1717

1818
* [Original](https://eslint.org/docs/rules/require-jsdoc)
1919
* [Source](../../lib/rules/redefined/require-jsdoc.js)
20-
* [Tests](../../test/eslint/rules/require-jsdoc.js)
20+
* [Tests](../../test/eslint/rules/redefined/require-jsdoc.js)

docs/redefined/valid-jsdoc.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ but doesn't when `interfaced/valid-jsdoc` is used.
2424

2525
* [Original](https://eslint.org/docs/rules/valid-jsdoc)
2626
* [Source](../../lib/rules/redefined/valid-jsdoc.js)
27-
* [Tests](../../test/eslint/rules/valid-jsdoc.js)
27+
* [Tests](../../test/eslint/rules/redefined/valid-jsdoc.js)

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module.exports.rules = {
22
'camelcase': require('./lib/rules/redefined/camelcase'),
3+
'no-param-reassign': require('./lib/rules/redefined/no-param-reassign'),
34
'no-unused-expressions': require('./lib/rules/redefined/no-unused-expressions'),
45
'require-jsdoc': require('./lib/rules/redefined/require-jsdoc'),
56
'valid-jsdoc': require('./lib/rules/redefined/valid-jsdoc'),

lib/ast-utils.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,32 @@ function isClass(node) {
6363
);
6464
}
6565

66+
/**
67+
* @param {ASTNode} node
68+
* @param {SourceCode} sourceCode
69+
* @return {boolean}
70+
*/
71+
function isTypecast(node, sourceCode) {
72+
const tokenBefore = sourceCode.getTokenBefore(node, {
73+
includeComments: true
74+
});
75+
76+
const tokenAfter = sourceCode.getTokenAfter(node, {
77+
includeComments: true
78+
});
79+
80+
return (
81+
tokenBefore &&
82+
tokenBefore.type === 'Punctuator' &&
83+
tokenBefore.value === '(' &&
84+
hasJSDocTags(tokenBefore, ['type'], sourceCode) &&
85+
86+
tokenAfter &&
87+
tokenAfter.type === 'Punctuator' &&
88+
tokenAfter.value === ')'
89+
);
90+
}
91+
6692
/**
6793
* @param {ASTNode} propExpression
6894
* @return {string}
@@ -524,6 +550,7 @@ module.exports = {
524550
isTypedefExpression,
525551
isConstantExpression,
526552
isClass,
553+
isTypecast,
527554
resolvePropName,
528555
resolveClassName,
529556
resolveParamNames,
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
const originalRule = require('eslint/lib/rules/no-param-reassign');
2+
3+
const {isTypecast} = require('../../ast-utils');
4+
const {deepShallowCopy} = require('../../utils');
5+
6+
module.exports = {
7+
meta: originalRule.meta,
8+
create: (context) => {
9+
const sourceCode = context.getSourceCode();
10+
const contextCopy = deepShallowCopy(context);
11+
12+
/**
13+
* @param {ASTNode} nodeA
14+
* @param {ASTNode} nodeB
15+
* @param {string} type
16+
* @return {boolean}
17+
*/
18+
function bothHaveType(nodeA, nodeB, type) {
19+
return nodeA.type === type && nodeB.type === type;
20+
}
21+
22+
/**
23+
* @param {ASTNode} nodeA
24+
* @param {ASTNode} nodeB
25+
* @return {boolean}
26+
*/
27+
function bothHaveSameName(nodeA, nodeB) {
28+
return nodeA.name === nodeB.name;
29+
}
30+
31+
contextCopy.report = (error) => {
32+
const {node} = error;
33+
34+
let assignment;
35+
if (node.parent.type === 'AssignmentExpression') {
36+
assignment = node.parent;
37+
} else if (node.parent.type === 'MemberExpression') {
38+
let ancestor = node.parent;
39+
while (ancestor.type === 'MemberExpression') {
40+
ancestor = ancestor.parent;
41+
}
42+
43+
if (ancestor.type === 'AssignmentExpression') {
44+
assignment = ancestor;
45+
}
46+
}
47+
48+
if (assignment && assignment.operator === '=') {
49+
const lhs = assignment.left;
50+
const rhs = assignment.right;
51+
52+
if (isTypecast(rhs, sourceCode)) {
53+
if (bothHaveType(lhs, rhs, 'Identifier') && bothHaveSameName(lhs, rhs)) {
54+
return;
55+
}
56+
57+
if (bothHaveType(lhs, rhs, 'MemberExpression')) {
58+
let lhsObject = lhs;
59+
let rhsObject = rhs;
60+
61+
let areIdentical = true;
62+
while (areIdentical) {
63+
if (bothHaveType(lhsObject, rhsObject, 'Identifier')) {
64+
areIdentical = bothHaveSameName(lhsObject, rhsObject);
65+
} else {
66+
areIdentical = (
67+
bothHaveType(lhsObject.property, rhsObject.property, 'Identifier') &&
68+
bothHaveSameName(lhsObject.property, rhsObject.property)
69+
);
70+
}
71+
72+
lhsObject = lhsObject.object;
73+
rhsObject = rhsObject.object;
74+
75+
if (!lhsObject || !rhsObject) {
76+
break;
77+
}
78+
}
79+
80+
if (areIdentical) {
81+
return;
82+
}
83+
}
84+
}
85+
}
86+
87+
context.report(error);
88+
};
89+
90+
return originalRule.create(contextCopy);
91+
}
92+
};

0 commit comments

Comments
 (0)