Skip to content

Commit ca5e4cb

Browse files
scalvertchadhietala
authored andcommitted
Adding new no-timers rule (#8)
Add rules around timers
1 parent 4a13457 commit ca5e4cb

File tree

7 files changed

+207
-36
lines changed

7 files changed

+207
-36
lines changed

guides/rules/no-timers.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# No Timers
2+

lib/rules/no-timers.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
1+
const { getParent } = require('../utils/get');
2+
const { isGuarded } = require('../utils/fast-boot');
3+
4+
const TIMERS = ['setTimeout', 'setInterval'];
5+
6+
const MESSAGE = 'Do not use timers. Please see the following guide for more infromation: http://github.com/chadhietala/ember-best-practices/files/guides/no-timers.md';
7+
18
function isTimer(name) {
2-
return name === 'setTimeout' || name === 'setInterval';
9+
return TIMERS.includes(name);
310
}
411

5-
const MESSAGE = '';
12+
function isInAction(node) {
13+
return !!getParent(node, (node) => node.type === 'Property' && node.key.name === 'actions');
14+
}
15+
16+
function getName(node) {
17+
if (!node.callee) {
18+
return '';
19+
}
20+
21+
return node.callee && (node.callee.name || (node.callee.property && node.callee.property.name));
22+
}
623

724
module.exports = {
825
meta: {
@@ -11,8 +28,9 @@ module.exports = {
1128
create(context) {
1229
return {
1330
CallExpression(node) {
14-
let name = node.callee.name || node.callee.property.name;
15-
if (isTimer(name)) {
31+
let name = getName(node);
32+
33+
if (name && isTimer(name) && !isInAction(node) && !isGuarded(node)) {
1634
context.report(node, MESSAGE);
1735
}
1836
}

lib/utils/computed-property.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const get = require('./get');
1+
const { get } = require('./get');
22
const { getCaller } = require('./caller');
33

44
function isCPDesc(node, method) {

lib/utils/fast-boot.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const { getParent } = require('../utils/get');
2+
3+
function isEnvironmentBrowser(node) {
4+
let callee = node.test.callee;
5+
6+
if (callee) {
7+
let obj = callee.object;
8+
let prop = callee.property;
9+
10+
return obj.name === 'environment' && prop.name === 'isBrowser';
11+
}
12+
13+
return false;
14+
}
15+
16+
function isGuarded(node) {
17+
return getParent(node, (node) => node.type === 'IfStatement' && isEnvironmentBrowser(node));
18+
}
19+
20+
module.exports = {
21+
isGuarded
22+
};

lib/utils/get.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module.exports = function get(node, path) {
1+
function get(node, path) {
22
let parts;
33
if (typeof path === 'string') {
44
parts = path.split('.');
@@ -18,4 +18,21 @@ module.exports = function get(node, path) {
1818
}
1919

2020
return property;
21+
}
22+
23+
function getParent(node, predicate) {
24+
while (node) {
25+
if (predicate(node)) {
26+
return node;
27+
}
28+
29+
node = node.parent;
30+
}
31+
32+
return null;
33+
}
34+
35+
module.exports = {
36+
get,
37+
getParent
2138
};

tests/lib/rules/no-timers.js

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
const rule = require('../../../lib/rules/no-timers');
2+
const MESSAGE = rule.meta.message;
3+
const RuleTester = require('eslint').RuleTester;
4+
const ruleTester = new RuleTester();
5+
6+
ruleTester.run('no-timers', rule, {
7+
valid: [
8+
{
9+
code: `
10+
export default Ember.Component.extend({
11+
actions: {
12+
foo() {
13+
setTimeout(() => {});
14+
}
15+
}
16+
});`,
17+
parserOptions: {
18+
ecmaVersion: 6,
19+
sourceType: 'module'
20+
}
21+
},
22+
{
23+
code: `
24+
export default Ember.Component.extend({
25+
guarded() {
26+
if (environment.isBrowser()) {
27+
setTimeout(() => {});
28+
}
29+
}
30+
});`,
31+
parserOptions: {
32+
ecmaVersion: 6,
33+
sourceType: 'module'
34+
}
35+
},
36+
{
37+
code: `
38+
export default Ember.Component.extend({
39+
guarded() {
40+
if (environment.isBrowser()) {
41+
setInterval(() => {});
42+
}
43+
}
44+
});`,
45+
parserOptions: {
46+
ecmaVersion: 6,
47+
sourceType: 'module'
48+
}
49+
}
50+
],
51+
invalid: [
52+
{
53+
code: `
54+
export default Ember.Component({
55+
bar() {
56+
setTimeout(() => {});
57+
}
58+
});`,
59+
parserOptions: {
60+
ecmaVersion: 6,
61+
sourceType: 'module'
62+
},
63+
errors: [{
64+
message: MESSAGE
65+
}]
66+
},
67+
{
68+
code: `
69+
export default Ember.Component({
70+
baz() {
71+
setInterval(() => {});
72+
}
73+
});`,
74+
parserOptions: {
75+
ecmaVersion: 6,
76+
sourceType: 'module'
77+
},
78+
errors: [{
79+
message: MESSAGE
80+
}]
81+
},
82+
{
83+
code: `
84+
export default Ember.Component({
85+
bar() {
86+
window.setTimeout(() => {});
87+
}
88+
});`,
89+
parserOptions: {
90+
ecmaVersion: 6,
91+
sourceType: 'module'
92+
},
93+
errors: [{
94+
message: MESSAGE
95+
}]
96+
},
97+
{
98+
code: `
99+
export default Ember.Component({
100+
baz() {
101+
window.setInterval(() => {});
102+
}
103+
});`,
104+
parserOptions: {
105+
ecmaVersion: 6,
106+
sourceType: 'module'
107+
},
108+
errors: [{
109+
message: MESSAGE
110+
}]
111+
}
112+
]
113+
});

yarn.lock

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
22
# yarn lockfile v1
3-
4-
53
acorn-jsx@^3.0.0:
64
version "3.0.1"
75
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
@@ -152,18 +150,18 @@ d@^0.1.1, d@~0.1.1:
152150
dependencies:
153151
es5-ext "~0.10.2"
154152

155-
156-
version "2.2.0"
157-
resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
158-
dependencies:
159-
ms "0.7.1"
160-
161153
debug@^2.1.1:
162154
version "2.3.3"
163155
resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c"
164156
dependencies:
165157
ms "0.7.2"
166158

159+
160+
version "2.2.0"
161+
resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
162+
dependencies:
163+
ms "0.7.1"
164+
167165
deep-is@~0.1.3:
168166
version "0.1.3"
169167
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
@@ -227,7 +225,7 @@ es6-set@~0.1.3:
227225
es6-symbol "3"
228226
event-emitter "~0.3.4"
229227

230-
es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0:
228+
es6-symbol@~3.1, es6-symbol@~3.1.0, es6-symbol@3:
231229
version "3.1.0"
232230
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa"
233231
dependencies:
@@ -243,7 +241,7 @@ es6-weak-map@^2.0.1:
243241
es6-iterator "2"
244242
es6-symbol "3"
245243

246-
[email protected].5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
244+
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, [email protected]:
247245
version "1.0.5"
248246
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
249247

@@ -384,9 +382,9 @@ glob-all@^3.0.1:
384382
glob "^7.0.5"
385383
yargs "~1.2.6"
386384

387-
388-
version "7.0.5"
389-
resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.5.tgz#b4202a69099bbb4d292a7c1b95b6682b67ebdc95"
385+
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5:
386+
version "7.1.1"
387+
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
390388
dependencies:
391389
fs.realpath "^1.0.0"
392390
inflight "^1.0.4"
@@ -395,9 +393,9 @@ [email protected]:
395393
once "^1.3.0"
396394
path-is-absolute "^1.0.0"
397395

398-
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5:
399-
version "7.1.1"
400-
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
396+
397+
version "7.0.5"
398+
resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.5.tgz#b4202a69099bbb4d292a7c1b95b6682b67ebdc95"
401399
dependencies:
402400
fs.realpath "^1.0.0"
403401
inflight "^1.0.4"
@@ -458,7 +456,7 @@ inflight@^1.0.4:
458456
once "^1.3.0"
459457
wrappy "1"
460458

461-
inherits@2, inherits@~2.0.1:
459+
inherits@~2.0.1, inherits@2:
462460
version "2.0.3"
463461
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
464462

@@ -626,15 +624,15 @@ minimatch@^3.0.2:
626624
dependencies:
627625
brace-expansion "^1.0.0"
628626

629-
630-
version "0.0.8"
631-
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
632-
633627
minimist@^0.1.0:
634628
version "0.1.0"
635629
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de"
636630

637-
[email protected], mkdirp@^0.5.0, mkdirp@^0.5.1:
631+
632+
version "0.0.8"
633+
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
634+
635+
mkdirp@^0.5.0, mkdirp@^0.5.1, [email protected]:
638636
version "0.5.1"
639637
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
640638
dependencies:
@@ -839,6 +837,10 @@ sprintf-js@~1.0.2:
839837
version "1.0.3"
840838
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
841839

840+
string_decoder@~0.10.x:
841+
version "0.10.31"
842+
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
843+
842844
string-width@^1.0.1:
843845
version "1.0.2"
844846
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
@@ -854,10 +856,6 @@ string-width@^2.0.0:
854856
is-fullwidth-code-point "^2.0.0"
855857
strip-ansi "^3.0.0"
856858

857-
string_decoder@~0.10.x:
858-
version "0.10.31"
859-
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
860-
861859
strip-ansi@^3.0.0:
862860
version "3.0.1"
863861
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
@@ -872,16 +870,16 @@ strip-json-comments@~1.0.1:
872870
version "1.0.4"
873871
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
874872

873+
supports-color@^2.0.0:
874+
version "2.0.0"
875+
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
876+
875877
876878
version "3.1.2"
877879
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5"
878880
dependencies:
879881
has-flag "^1.0.0"
880882

881-
supports-color@^2.0.0:
882-
version "2.0.0"
883-
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
884-
885883
table@^3.7.8:
886884
version "3.8.3"
887885
resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
@@ -948,3 +946,4 @@ yargs@~1.2.6:
948946
resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.2.6.tgz#9c7b4a82fd5d595b2bf17ab6dcc43135432fe34b"
949947
dependencies:
950948
minimist "^0.1.0"
949+

0 commit comments

Comments
 (0)