Skip to content

Commit 7604b1e

Browse files
authored
Adding new rule: require-ember-lifeline (#62)
* Adding new rule: require-ember-lifeline
1 parent 63e7d67 commit 7604b1e

File tree

3 files changed

+618
-0
lines changed

3 files changed

+618
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Require Ember Lifeline
2+
3+
[Ember lifeline](https://github.com/rwjblue/ember-lifeline)
4+
5+
Ember applications have long life-cycles. A user may navigate to several pages and use many different features before they leave the application. This makes JavaScript and Ember development unlike Rails development, where the lifecycle of a request is short and the environment disposed of after each request. It makes Ember development much more like iOS or video game development than traditional server-side web development.
6+
7+
It is good to note that this isn't something inherent to just Ember. Any single-page app framework or solution (Angular, React, Vue, Backbone...) must deal with the lifecycles of objects, and specifically with how async tasks can be bounded by a lifecycle.
8+
9+
Ember lifeline introduces several utility methods to help manage async, object lifecycles, and the Ember runloop. Please review the documentation to understand the APIs that can be used to replace the equivalent `Ember.run` method.

lib/rules/require-ember-lifeline.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* @fileOverview Require the use of ember-lifeline's lifecycle aware methods over Ember.run.*.
3+
*/
4+
5+
const { getCaller, cleanCaller } = require('../utils/caller');
6+
const { getEmberImportBinding } = require('../utils/imports');
7+
const { collectObjectPatternBindings } = require('../utils/destructed-binding');
8+
9+
let DISALLOWED_OBJECTS = ['Ember.run', 'run'];
10+
let RUN_METHODS = ['later', 'next', 'debounce', 'throttle'];
11+
const LIFELINE_METHODS = ['runTask', 'runTask', 'debounceTask', 'throttleTask'];
12+
13+
function getMessage(actualMethodUsed) {
14+
let method = actualMethodUsed.split('.').pop();
15+
let lifelineEquivalent = LIFELINE_METHODS[RUN_METHODS.indexOf(method)];
16+
17+
return `Please use ${lifelineEquivalent} from ember-lifeline instead of ${actualMethodUsed}.`;
18+
}
19+
20+
function mergeDisallowedCalls(objects) {
21+
return objects
22+
.reduce((calls, obj) => {
23+
RUN_METHODS.forEach((method) => {
24+
calls.push(`${obj}.${method}`);
25+
});
26+
27+
return calls;
28+
}, []);
29+
}
30+
31+
module.exports = {
32+
docs: {
33+
description: 'Please use the lifecycle-aware tasks from ember-lifeline instead of Ember.run.*.',
34+
category: 'Best Practices',
35+
recommended: false
36+
},
37+
meta: {
38+
message: getMessage
39+
},
40+
create(context) {
41+
let emberImportBinding;
42+
let disallowedCalls = mergeDisallowedCalls(DISALLOWED_OBJECTS);
43+
44+
return {
45+
ImportDefaultSpecifier(node) {
46+
emberImportBinding = getEmberImportBinding(node);
47+
},
48+
49+
ObjectPattern(node) {
50+
if (emberImportBinding) {
51+
disallowedCalls = disallowedCalls.concat(
52+
mergeDisallowedCalls(
53+
collectObjectPatternBindings(node, {
54+
[emberImportBinding]: ['run']
55+
})
56+
)
57+
);
58+
}
59+
},
60+
61+
MemberExpression(node) {
62+
let caller = cleanCaller(getCaller(node));
63+
64+
if (disallowedCalls.includes(caller)) {
65+
context.report(node, getMessage(caller));
66+
}
67+
}
68+
};
69+
}
70+
};

0 commit comments

Comments
 (0)