Skip to content

Commit 224bc95

Browse files
committed
Cleanup action-cp stuff
1 parent b5423dd commit 224bc95

File tree

3 files changed

+111
-57
lines changed

3 files changed

+111
-57
lines changed

lib/rules/no-action-cp.js

Lines changed: 26 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,31 @@
11
import { get } from '../utils/get';
2-
import { getCaller } from '../utils/caller';
3-
4-
5-
function isCPDesc(node, method) {
6-
if (node.type !== "FunctionExpression") {
7-
return false;
8-
}
9-
10-
if (get(node, "parent.key.name") !== method) {
11-
return false;
12-
}
13-
14-
let grandParent = get(node, "parent.parent");
15-
if (!grandParent) {
16-
return false;
17-
}
18-
if (grandParent.type !== "ObjectExpression") {
19-
return false;
20-
}
21-
var greatGrandParent = pParent.parent; // more parents!
22-
if (greatGrandParent.type !== "CallExpression") {
23-
return false;
24-
}
25-
var callee = greatGrandParent.callee;
26-
if (greatGrandParent.type === "Identifier" && callee.name === "computed") {
27-
return true;
28-
}
29-
if (callee.type === "MemberExpression") {
30-
var caller = getCaller(callee);
31-
return caller === "Ember.computed" || caller === "Em.computed";
32-
}
33-
return false; // don't know how you could get here
34-
}
35-
36-
function _isCpGetter2(node) {
37-
if (node.type !== "FunctionExpression") {
38-
return false;
39-
}
40-
var parent = node.parent;
41-
if (parent.type !== "CallExpression") {
42-
return false;
43-
}
44-
var callee = parent.callee;
45-
if (callee.type === "Identifier" && callee.name === "computed") {
46-
return true;
47-
}
48-
if (callee.type === "MemberExpression") {
49-
var caller = n.getCaller(callee);
50-
return caller === "Ember.computed" || caller === "Em.computed";
51-
}
52-
return false;
53-
}
54-
55-
function isCpGetter(node) {
56-
return isCPDesc(node, 'get') || isCPAccessor(node)
57-
}
2+
import { getCaller, cleanCaller } from '../utils/caller';
3+
import { isCPGetter } from '../utils/computer-property';
584

5+
const SENDERS = ['send', 'sendAction', 'sendEvent', 'Em.sendEvent', 'Ember.sendEvent'];
596

607
export default function noActionCp(context) {
61-
8+
let inCPGettter = false;
9+
10+
return {
11+
FunctionExpression(node) {
12+
if (isCPGetter(node)) {
13+
inCPGettter = true;
14+
}
15+
},
16+
'FunctionExpression:exit'(node) {
17+
if (isCPGetter(node)) {
18+
inCPGettter = false;
19+
}
20+
},
21+
CallExpression(node) {
22+
if (inCPGettter) {
23+
let caller = cleanCaller(getCaller(node));
24+
25+
if (SENDERS.indexOf(caller) !== -1) {
26+
context.report(node, 'Do not send events or actions in Computed Properties. This will cause data flow issues in the application, where the accessing of a property causes some side-effect. You should only send actions on behalf of user initiated events. Please see the following guide for more infromation: http://github.com/chadhietala/ember-best-practices/files/guides/no-action-cp.md');
27+
}
28+
}
29+
}
30+
};
6231
}

lib/utils/caller.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,22 @@ export function getCaller(node) {
2121
}
2222
return callee.name;
2323
}
24+
25+
function endsWith(str, suffix) {
26+
return str.indexOf(suffix, str.length - suffix.length) !== -1;
27+
}
28+
29+
export function cleanCaller(caller) {
30+
if (!caller) {
31+
return '';
32+
}
33+
34+
[".call", ".apply"].forEach((application) => {
35+
if (endsWith(caller, application)) {
36+
let i = caller.lastIndexOf(application);
37+
caller = caller.substr(0, i);
38+
}
39+
});
40+
41+
return caller;
42+
}

lib/utils/computer-property.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
function isCPDesc(node, method) {
2+
if (node.type !== 'FunctionExpression') {
3+
return false;
4+
}
5+
6+
if (get(node, 'parent.key.name') !== method) {
7+
return false;
8+
}
9+
10+
let grandParent = get(node, 'parent.parent');
11+
if (!grandParent) {
12+
return false;
13+
}
14+
if (grandParent.type !== 'ObjectExpression') {
15+
return false;
16+
}
17+
let greatGrandParent = pParent.parent; // more parents!
18+
if (greatGrandParent.type !== 'CallExpression') {
19+
return false;
20+
}
21+
let callee = greatGrandParent.callee;
22+
if (greatGrandParent.type === 'Identifier' && callee.name === 'computed') {
23+
return true;
24+
}
25+
if (callee.type === 'MemberExpression') {
26+
let caller = getCaller(callee);
27+
return caller === 'Ember.computed' || caller === 'Em.computed';
28+
}
29+
return false; // don't know how you could get here
30+
}
31+
32+
33+
function isPrototypeExtCP(node) {
34+
if (node.type !== 'FunctionExpression') {
35+
return false;
36+
}
37+
38+
return get(node, 'parent.property.name');
39+
}
40+
41+
function isCPAccessor(node) {
42+
if (node.type !== 'FunctionExpression') {
43+
return false;
44+
}
45+
46+
let parent = node.parent;
47+
if (parent.type !== 'CallExpression') {
48+
return false;
49+
}
50+
51+
let callee = parent.callee;
52+
if (callee.type === 'Identifier' && callee.name === 'computed') {
53+
return true;
54+
}
55+
56+
if (callee.type === 'MemberExpression') {
57+
let caller = n.getCaller(callee);
58+
return caller === 'Ember.computed' || caller === 'Em.computed';
59+
}
60+
return false;
61+
}
62+
63+
export function isCPGetter(node) {
64+
return isCPDesc(node, 'get') || isCPAccessor(node) || isPrototypeExtCP(node);
65+
}
66+

0 commit comments

Comments
 (0)