Skip to content

Commit

Permalink
Adding new rule: require-ember-lifeline (#62)
Browse files Browse the repository at this point in the history
* Adding new rule: require-ember-lifeline
  • Loading branch information
scalvert committed Jun 26, 2017
1 parent 63e7d67 commit 7604b1e
Show file tree
Hide file tree
Showing 3 changed files with 618 additions and 0 deletions.
9 changes: 9 additions & 0 deletions guides/rules/require-ember-lifeline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Require Ember Lifeline

[Ember lifeline](https://github.com/rwjblue/ember-lifeline)

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.

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.

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.
70 changes: 70 additions & 0 deletions lib/rules/require-ember-lifeline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* @fileOverview Require the use of ember-lifeline's lifecycle aware methods over Ember.run.*.
*/

const { getCaller, cleanCaller } = require('../utils/caller');
const { getEmberImportBinding } = require('../utils/imports');
const { collectObjectPatternBindings } = require('../utils/destructed-binding');

let DISALLOWED_OBJECTS = ['Ember.run', 'run'];
let RUN_METHODS = ['later', 'next', 'debounce', 'throttle'];
const LIFELINE_METHODS = ['runTask', 'runTask', 'debounceTask', 'throttleTask'];

function getMessage(actualMethodUsed) {
let method = actualMethodUsed.split('.').pop();
let lifelineEquivalent = LIFELINE_METHODS[RUN_METHODS.indexOf(method)];

return `Please use ${lifelineEquivalent} from ember-lifeline instead of ${actualMethodUsed}.`;
}

function mergeDisallowedCalls(objects) {
return objects
.reduce((calls, obj) => {
RUN_METHODS.forEach((method) => {
calls.push(`${obj}.${method}`);
});

return calls;
}, []);
}

module.exports = {
docs: {
description: 'Please use the lifecycle-aware tasks from ember-lifeline instead of Ember.run.*.',
category: 'Best Practices',
recommended: false
},
meta: {
message: getMessage
},
create(context) {
let emberImportBinding;
let disallowedCalls = mergeDisallowedCalls(DISALLOWED_OBJECTS);

return {
ImportDefaultSpecifier(node) {
emberImportBinding = getEmberImportBinding(node);
},

ObjectPattern(node) {
if (emberImportBinding) {
disallowedCalls = disallowedCalls.concat(
mergeDisallowedCalls(
collectObjectPatternBindings(node, {
[emberImportBinding]: ['run']
})
)
);
}
},

MemberExpression(node) {
let caller = cleanCaller(getCaller(node));

if (disallowedCalls.includes(caller)) {
context.report(node, getMessage(caller));
}
}
};
}
};
Loading

0 comments on commit 7604b1e

Please sign in to comment.