Skip to content

Commit

Permalink
Merge pull request #1073 from bmish/jquery-ember-run-run-functions
Browse files Browse the repository at this point in the history
Allow any Ember runloop function in `jquery-ember-run` rule
  • Loading branch information
bmish authored Jan 26, 2021
2 parents b50e26c + 417733f commit c879157
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 12 deletions.
2 changes: 1 addition & 1 deletion docs/rules/jquery-ember-run.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Don’t use jQuery without the Ember Run Loop.

Using plain jQuery invokes actions out of the Ember Run Loop. In order to have a control on all operations in Ember, it's good practice to trigger actions in run loop.
Using plain jQuery invokes actions outside of the Ember Run Loop. In order to have a control on all operations in Ember, it's good practice to trigger actions in a run loop (using one of the [@ember/runloop](https://api.emberjs.com/ember/3.24/classes/@ember%2Frunloop) functions).

## Examples

Expand Down
30 changes: 25 additions & 5 deletions lib/rules/jquery-ember-run.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ const { globalMap, esmMap } = require('../utils/jquery');

const ERROR_MESSAGE = "Don't use jQuery without Ember Run Loop";

// https://api.emberjs.com/ember/3.24/classes/@ember%2Frunloop
const EMBER_RUNLOOP_FUNCTIONS = [
'begin',
'bind',
'cancel',
'debounce',
'end',
'join',
'later',
'next',
'once',
'run',
'schedule',
'scheduleOnce',
'throttle',
];

module.exports = {
meta: {
type: 'problem',
Expand All @@ -34,7 +51,7 @@ module.exports = {
};

let importedEmberName;
let importedBindName;
const importedRunloopFunctions = [];

function checkJqueryCall(node) {
if (
Expand All @@ -57,14 +74,14 @@ module.exports = {
const isBindCall =
types.isCallExpression(expression) &&
expression.callee.type === 'Identifier' &&
expression.callee.name === importedBindName;
importedRunloopFunctions.includes(expression.callee.name);

// Check for old-style: Ember.run.bind()
const isEmberBindCall =
types.isCallExpression(expression) &&
expression.callee.type === 'MemberExpression' &&
expression.callee.property.type === 'Identifier' &&
expression.callee.property.name === 'bind' &&
EMBER_RUNLOOP_FUNCTIONS.includes(expression.callee.property.name) &&
expression.callee.object.type === 'MemberExpression' &&
expression.callee.object.property.type === 'Identifier' &&
expression.callee.object.property.name === 'run' &&
Expand All @@ -85,8 +102,11 @@ module.exports = {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');
}
if (node.source.value === '@ember/runloop') {
importedBindName =
importedBindName || getImportIdentifier(node, '@ember/runloop', 'bind');
importedRunloopFunctions.push(
...EMBER_RUNLOOP_FUNCTIONS.map((fn) =>
getImportIdentifier(node, '@ember/runloop', fn)
).filter((fn) => fn !== undefined)
);
}
},

Expand Down
24 changes: 18 additions & 6 deletions tests/lib/rules/jquery-ember-run.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ eslintTester.run('jquery-ember-run', rule, {
// jQuery/bind from Ember
`import Ember from "ember";
Ember.$("#item").on("click", () => { Ember.run.bind(this, this.handle); });`,
`import Ember from "ember";
Ember.$("#item").on("click", () => { Ember.run.debounce(this, this.handle); });`,

// jQuery from Ember with destructuring
`import Ember from "ember";
Expand All @@ -37,6 +39,9 @@ eslintTester.run('jquery-ember-run', rule, {
`import { bind } from "@ember/runloop";
import $ from "jquery";
$("#item").on("click", () => { bind(this, this.handle); });`,
`import { debounce } from "@ember/runloop";
import $ from "jquery";
$("#item").on("click", () => { debounce(this, this.handle); });`,

// No callback
'import $ from "jquery"; $("#item");',
Expand Down Expand Up @@ -78,28 +83,35 @@ eslintTester.run('jquery-ember-run', rule, {
errors: [{ message: ERROR_MESSAGE, type: 'MemberExpression' }],
},
{
// With function call that isn't `bind`
code: 'import $ from "jquery"; $("#item").on("click", () => { notBind(); });',
// With function call that isn't a runloop function
code: 'import $ from "jquery"; $("#item").on("click", () => { unknownFunction(); });',
output: null,
errors: [{ message: ERROR_MESSAGE, type: 'Identifier' }],
},
{
// With unknown imported runloop function
code:
'import { unknownFunction } from "@ember/runloop"; import $ from "jquery"; $("#item").on("click", () => { unknownFunction(); });',
output: null,
errors: [{ message: ERROR_MESSAGE, type: 'Identifier' }],
},
{
// With function call that isn't `Ember`
// With not from Ember
code: 'import $ from "jquery"; $("#item").on("click", () => { notEmber.run.bind(); });',
output: null,
errors: [{ message: ERROR_MESSAGE, type: 'MemberExpression' }],
},
{
// With function call that isn't `run`
// With not from Ember.run
code:
'import Ember from "ember"; import $ from "jquery"; $("#item").on("click", () => { Ember.notRun.bind(); });',
output: null,
errors: [{ message: ERROR_MESSAGE, type: 'MemberExpression' }],
},
{
// With function call that isn't `bind`
// With unknown function call from Ember.run
code:
'import Ember from "ember"; import $ from "jquery"; $("#item").on("click", () => { Ember.run.notBind(); });',
'import Ember from "ember"; import $ from "jquery"; $("#item").on("click", () => { Ember.run.unknownFunction(); });',
output: null,
errors: [{ message: ERROR_MESSAGE, type: 'MemberExpression' }],
},
Expand Down

0 comments on commit c879157

Please sign in to comment.