Skip to content

Commit 67f1fd9

Browse files
authored
Merge pull request #973 from bachvo/deprecate-tryinvoke
Add new rule `no-try-invoke`
2 parents bf94f66 + b5768d6 commit 67f1fd9

File tree

5 files changed

+131
-0
lines changed

5 files changed

+131
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ Rules are grouped by category to help you understand their purpose. Each rule ha
124124
| :white_check_mark::wrench: | [no-get-with-default](./docs/rules/no-get-with-default.md) | disallow usage of the Ember's `getWithDefault` function |
125125
| :white_check_mark::wrench: | [no-get](./docs/rules/no-get.md) | require using ES5 getters instead of Ember's `get` / `getProperties` functions |
126126
| | [no-proxies](./docs/rules/no-proxies.md) | disallow using array or object proxies |
127+
| | [no-try-invoke](./docs/rules/no-try-invoke.md) | disallow usage of the Ember's `tryInvoke` util |
127128
| :white_check_mark::wrench: | [require-super-in-init](./docs/rules/require-super-in-init.md) | require super to be called in lifecycle hooks |
128129
| :wrench: | [use-ember-get-and-set](./docs/rules/use-ember-get-and-set.md) | enforce usage of `Ember.get` and `Ember.set` |
129130

docs/rules/no-try-invoke.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# no-try-invoke
2+
3+
This rule will catch and prevent the use of `tryInvoke`.
4+
5+
## Rule Details
6+
7+
This rule aims to disallow the usage of `tryInvoke`. Native JavaScript language now supports [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) and developers are encouraged to use optional chaining `?.()` instead.
8+
9+
## Examples
10+
11+
Examples of **incorrect** code for this rule:
12+
13+
```js
14+
import { tryInvoke } from '@ember/utils';
15+
16+
class FooComponent extends Component {
17+
foo() {
18+
tryInvoke(this.args, 'bar', ['baz']);
19+
}
20+
}
21+
```
22+
23+
Examples of **correct** code for this rule:
24+
25+
```js
26+
class FooComponent extends Component {
27+
foo() {
28+
this.args.bar?.('baz');
29+
}
30+
}
31+
```
32+
33+
## References
34+
35+
- [RFC](https://github.com/emberjs/rfcs/pull/673) to deprecate `tryInvoke`
36+
- [spec](https://api.emberjs.com/ember/release/functions/@ember%2Futils/tryInvoke)

lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ module.exports = {
5858
'no-test-module-for': require('./rules/no-test-module-for'),
5959
'no-test-support-import': require('./rules/no-test-support-import'),
6060
'no-test-this-render': require('./rules/no-test-this-render'),
61+
'no-try-invoke': require('./rules/no-try-invoke'),
6162
'no-unnecessary-index-route': require('./rules/no-unnecessary-index-route'),
6263
'no-unnecessary-route-path-option': require('./rules/no-unnecessary-route-path-option'),
6364
'no-unnecessary-service-injection-argument': require('./rules/no-unnecessary-service-injection-argument'),

lib/rules/no-try-invoke.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
3+
const types = require('../utils/types');
4+
const { getImportIdentifier } = require('../utils/import');
5+
6+
const ERROR_MESSAGE = 'Use optional chaining operator `?.()` instead of `tryInvoke`';
7+
8+
module.exports = {
9+
ERROR_MESSAGE,
10+
meta: {
11+
type: 'suggestion',
12+
docs: {
13+
description: "disallow usage of the Ember's `tryInvoke` util",
14+
category: 'Ember Object',
15+
recommended: false,
16+
url:
17+
'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/no-try-invoke.md',
18+
},
19+
fixable: null,
20+
schema: [],
21+
},
22+
23+
create(context) {
24+
let importedTryInvokeName;
25+
26+
return {
27+
ImportDeclaration(node) {
28+
const importSource = node.source.value;
29+
30+
if (importSource === '@ember/utils') {
31+
importedTryInvokeName =
32+
importedTryInvokeName || getImportIdentifier(node, '@ember/utils', 'tryInvoke');
33+
}
34+
},
35+
36+
CallExpression(node) {
37+
if (types.isIdentifier(node.callee) && node.callee.name === importedTryInvokeName) {
38+
context.report({
39+
node,
40+
message: ERROR_MESSAGE,
41+
});
42+
}
43+
},
44+
};
45+
},
46+
};

tests/lib/rules/no-try-invoke.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const rule = require('../../../lib/rules/no-try-invoke');
2+
const RuleTester = require('eslint').RuleTester;
3+
4+
const { ERROR_MESSAGE } = rule;
5+
const ruleTester = new RuleTester({
6+
parserOptions: {
7+
ecmaVersion: 2018,
8+
sourceType: 'module',
9+
},
10+
});
11+
12+
ruleTester.run('no-try-invoke', rule, {
13+
valid: [
14+
"tryInvoke(this, 'foo');",
15+
"import { tryInvoke } from '@ember/utils'; foo.tryInvoke(this, 'foo');",
16+
"import { tryInvoke } from '@ember/utils'; tryInvoke.foo(this, 'foo');",
17+
"import { tryInvoke } from '@ember/utils'; foo();",
18+
],
19+
invalid: [
20+
{
21+
code: `
22+
import { tryInvoke } from '@ember/utils';
23+
tryInvoke(this, 'foo');
24+
`,
25+
output: null,
26+
errors: [
27+
{
28+
message: ERROR_MESSAGE,
29+
type: 'CallExpression',
30+
},
31+
],
32+
},
33+
{
34+
code: `
35+
import { tryInvoke, isPresent } from '@ember/utils';
36+
tryInvoke(this, 'foo', ['bar']);
37+
`,
38+
output: null,
39+
errors: [
40+
{
41+
message: ERROR_MESSAGE,
42+
type: 'CallExpression',
43+
},
44+
],
45+
},
46+
],
47+
});

0 commit comments

Comments
 (0)