Skip to content

Guard against key-less nodes. Fixes #71 #72

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0b4399a
Remove default BLACKLIST
lynchbomb Jul 26, 2017
c3bcdca
Update no-jquery-methods.md
lynchbomb Aug 2, 2017
03d470f
Check node type for lib/utils/imports.collectImportBindings
shamcode Aug 7, 2017
f392997
Update CHANGELOG and AUTHORS for 0.8.0
lynchbomb Aug 15, 2017
eafee52
0.8.0
lynchbomb Aug 15, 2017
30b6916
Implement rule for anonymous functions passed to scheduleOnce and once
eddie-ruva Aug 19, 2017
ac5df8a
Add linting for CallExpessions like $.ajax()
nlfurniss Aug 30, 2017
b94cdd3
Add doc explaining how to generate blacklist array
nlfurniss Aug 30, 2017
9a26687
Remove Ember from isJQueryCaller check
nlfurniss Aug 30, 2017
bb91826
Increase test coverage for no-jquery-methods and bump authors
nlfurniss Aug 30, 2017
e9d70a0
Guard propertyName in no-jquery-methods
nlfurniss Aug 30, 2017
9b3da80
Update CHANGELOG and AUTHORS for 0.9.0
lynchbomb Aug 31, 2017
55730db
0.9.0
lynchbomb Aug 31, 2017
8680be8
Create no-jquery-selector rule
nlfurniss Aug 31, 2017
7ece7fd
Fix logic to detect jQuery being assigned to a var
nlfurniss Sep 5, 2017
aaa7c0d
Fix no-global-jquery returning false positive for var assignment #85
nlfurniss Sep 6, 2017
68f8bc9
Rethink detecting global jquery var assignments
nlfurniss Sep 8, 2017
1eea3d6
Add fuctionality and tests for more global jquery cases
nlfurniss Sep 9, 2017
7957085
Handle local jquery vars in no-jquery-methods
nlfurniss Sep 11, 2017
5c3cdfc
Fix no-anonymous-once not recognizing context function
nlfurniss Sep 12, 2017
5815778
Update CHANGELOG for 1.0.0
nlfurniss Sep 13, 2017
ab5d1b1
1.0.0
Sep 13, 2017
a41bf53
DRY up `parserOptions`
nlfurniss Sep 14, 2017
d2a591c
Fixes require-ember-lifeline rule to scope it to only ember file type…
scalvert Oct 1, 2017
9e307f9
Add missing tests (#91)
hjdivad Oct 3, 2017
c66fddf
Update CHANGELOG and AUTHORS for 1.1.0
scalvert Oct 3, 2017
ab51a06
1.1.0
scalvert Oct 3, 2017
cb794cc
Add tests for jquery util methods (#90)
nlfurniss Nov 3, 2017
62071ae
[BUG FIX] Cannot read property `getFilename` of undefined
sangm Nov 12, 2017
5950e5e
Add 1.1.1 to the CHANGELOG.md and update AUTHORS.txt.
Nov 13, 2017
475ffb1
v1.1.1
Nov 13, 2017
0d29a19
Guard against key-less nodes. Fixes #71
mwpastore Jul 7, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
/libpeerconnection.log
npm-debug.log
testem.log
/.vscode
8 changes: 8 additions & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
Burnashov Evgeny <[email protected]>
Chad Hietala <[email protected]>
Chris Thoburn <[email protected]>
David J. Hamilton <[email protected]>
Edilberto Ruvalcaba <[email protected]>
Edilberto Ruvalcaba <[email protected]>
Ilya Radchenko <[email protected]>
Justin Lan <[email protected]>
Katie Gengler <[email protected]>
Kyle Turney <[email protected]>
Marc Lynch <[email protected]>
Marc Lynch <[email protected]>
Mikael Riska <[email protected]>
Nathaniel Furniss <[email protected]>
Nathaniel Furniss <[email protected]>
Quinn C. Hoyer <[email protected]>
Robert Jackson <[email protected]>
Robert Jackson <[email protected]>
Ryunosuke Sato <[email protected]>
Sang Mercado <[email protected]>
Sean Johnson <[email protected]>
Sean Johnson <[email protected]>
Stefan Penner <[email protected]>
Expand Down
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
1.1.1 / 2017-11-13
==================

* Fix issues when running under eslint@4 (fixes `Cannot read property 'getFilename' of undefined`).

1.1.0 / 2017-10-03
==================

* Fixes issues with imports (#91)
* Fixes require-ember-lifeline rule to scope it to only ember file types (#93)
* Merge pull request #89 from nlfurniss/dry-parserOptions

1.0.0 / 2017-09-13
==================

* Fix `no-anonymous-once` not recognizing context function
* Fix `no-global-jquery` returning false positive for var assignment #85
* Fix logic to detect jQuery being assigned to a var
* Create `no-jquery-selector` rule

0.9.0 / 2017-08-31
==================

* Fixing rule `no-jquery-methods` to remove reference to `Ember`
* Add tests for rule `no-jquery-methods`
* Update docs and rule `no-jquery-methods` to include checks for CallExpressions
* Adding new rule: `no-anonymous-once`

0.8.0 / 2017-08-15
==================

* Add test for rule `no-side-effect-cp`
* Fix `imports` util
* Update guide for `no-jquery-method`
* Update default BLACKLIST from config `no-jquery`
* Fix RELEASE.md

0.7.1 / 2017-06-27
==================
Expand Down
87 changes: 1 addition & 86 deletions config/no-jquery.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,3 @@
const BLACKLIST = [
'add',
'addBack',
'after',
'ajaxComplete',
'ajaxError',
'ajaxSend',
'ajaxStart',
'ajaxStop',
'ajaxSuccess',
'andSelf',
'before',
'bind',
'change',
'clearQueue',
'clone',
'contents',
'contextmenu',
'dblclick',
'delay',
'delegate',
'dequeue',
'detach',
'end',
'error',
'fadeIn',
'fadeTo',
'fadeToggle',
'finish',
'focusin',
'focusout',
'hover',
'insertAfter',
'insertBefore',
'keydown',
'keypress',
'keyup',
'last',
'load',
'mousedown',
'mouseenter',
'mouseleave',
'mousemove',
'mouseout',
'mouseover',
'mouseup',
'next',
'nextAll',
'nextUntil',
'not',
'parentsUntil',
'prepend',
'prependTo',
'prev',
'revUntil',
'promise',
'queue',
'removeData',
'removeProp',
'replaceAll',
'replaceWith',
'resize',
'scroll',
'scrollLeft',
'select',
'serialize',
'show',
'size',
'slice',
'slideDown',
'slideToggle',
'stop',
'submit',
'toArray',
'toggle',
'toggleClass',
'unbind',
'undelegate',
'unload',
'unwrap',
'wrap',
'wrapAll',
'wrapInner'
];

module.exports = {
parserOptions: {
ecmaVersion: 6,
Expand All @@ -97,6 +12,6 @@ module.exports = {
extends: require.resolve('./recommended.js'),
rules: {
// Custom rules
'ember-best-practices/no-jquery-methods': [2, [BLACKLIST]]
'ember-best-practices/no-jquery-methods': [2, []]
}
};
1 change: 1 addition & 0 deletions config/recommended.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = {
rules: {
// Custom rules
'ember-best-practices/no-side-effect-cp': 2,
'ember-best-practices/no-anonymous-once': 2,
'ember-best-practices/no-attrs': 2,
'ember-best-practices/no-observers': 2,
'ember-best-practices/require-dependent-keys': 2,
Expand Down
25 changes: 24 additions & 1 deletion guides/rules/no-jquery-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,28 @@

**TL;DR** The intent of this rule is to identify any blacklisted jQuery methods as deprecated.

Provides the ability to blacklist a set of jQuery methods for deprecation.
Provides the ability to blacklist a set of jQuery methods for deprecation.
The eventual goal being a complete removal of jQuery.

# Usage

Pass an argument array containing the specific blacklisted jQuery methods your consuming application is flagging for.

```js
const BLACKLIST = [
'add',
'addBack',
'after',
'ajaxComplete'
];

rules: {
'ember-best-practices/no-jquery-methods': ['error', BLACKLIST]
}
```
To help generate this blacklist array, you can run this snippet in the console of your app:
```js
// In the dev tools console of your app.
let $methods = [...new Set(Object.keys($).concat(Object.keys($.fn)))];
copy(`'${$methods.join('\',\r\n\'')}'`)
```
29 changes: 29 additions & 0 deletions guides/rules/no-jquery-selector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# No jQuery Selector

**TL;DR** The intent of this rule is to identify using jQuery to select DOM elements as deprecated.

# Examples

```js
// Deprecated
export default Ember.Component({
getElement(selector) {
return this.$(selector);
},

click() {
this.$().focus();
}
});

// Vanilla JS
export default Ember.Component({
getElement(selector) {
return this.element.querySelector(selector);
},

click() {
this.element.focus();
}
});
```
6 changes: 4 additions & 2 deletions lib/rules/no-2.0.0-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/
'use strict';

const { get } = require('../utils/get');

// TODO
// Write docs for this once we feel it should be recommended.
const MESSAGE = 'Do not use the 2.0.0 hooks as they are not conducive to the programming model.';
Expand All @@ -21,8 +23,8 @@ module.exports = {
return {
ObjectExpression(node) {
node.properties.forEach((property) => {
let name = property.key.name;
if (MISTAKE_HOOKS.indexOf(name) > -1) {
let name = get(property, 'key.name');
if (name && MISTAKE_HOOKS.indexOf(name) > -1) {
context.report(property, MESSAGE);
}
});
Expand Down
132 changes: 132 additions & 0 deletions lib/rules/no-anonymous-once.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* @fileOverview Disallow the use of anonymous functions passed to scheduleOnce and once.
*/
'use strict';

const { getCaller, cleanCaller, isCallingWithApply, isCallingWithCall } = require('../utils/caller');
const { collectObjectPatternBindings } = require('../utils/destructed-binding');
const { getEmberImportBinding } = require('../utils/imports');
const { get } = require('../utils/get');
const MESSAGE
= `The uniqueness once offers is based on function uniqueness, each invocation of this line will always create a new
function instance, resulting in uniqueness checks, that will never be hit. Please replace with a named function.
Reference: https://emberjs.com/api/ember/2.14/namespaces/Ember.run/methods/scheduleOnce?anchor=scheduleOnce`;

const DISALLOWED_OBJECTS = ['Ember.run', 'run'];
const SCHEDULE_ONCE = 'scheduleOnce';
const RUN_METHODS = [SCHEDULE_ONCE, 'once'];

/**
* Extracts the method that we are trying to run once from the list of arguments.
* An optional target parameter can be passed in as the first parameter so we need
* to check the length of the array to determine where our function is being passed in.
*/
function getMethodToRunOnce(args) {
return args.length > 1 ? args[1] : args[0];
}

/**
* scheduleOnce takes in the queue name as the first parameter. In this function we will remove
* that parameter from the array to make it look the same as the arguments to once and facilitate
* extracting the method that we are trying to run once out of the args.
*/
function normalizeArguments(caller, args) {
let mut = args.slice();

if (isCallingWithCall(caller)) {
// Whenever the action was called .call we want to remove the context parameter
mut.shift();
} else if (isCallingWithApply(caller)) {
// Whenever the action was called with .apply we want to get the arguments with which the function
// would actually get called
mut = mut[1].elements.slice();
}

// scheduleOnce takes in the queue name as the first parameter so we have to remove it have a similar
// structure as "once"
if (cleanCaller(caller).indexOf(SCHEDULE_ONCE) > -1) {
mut.shift();
}

return mut;
}
/**
* Determines whether a function is anonymous based on whether it was a name
* or if it is a method on the current context.
* @param {ASTNode} fn
* @return {Boolean}
*/
function isAnonymousFunction(fn) {
return !(get(fn, 'name') || get(fn, 'object.type') === 'ThisExpression');
}

function isString(node) {
return node.type === 'Literal' && typeof node.value === 'string';
}

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

return calls;
}, []);
}

module.exports = {
docs: {
description: 'Disallow use of anonymous functions when use in scheduleOnce or once',
category: 'Best Practices',
recommended: true
},
meta: {
message: MESSAGE
},
create(context) {
let emberImportBinding;
let disallowedCalls = mergeDisallowedCalls(DISALLOWED_OBJECTS);

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

ObjectPattern(node) {
if (!emberImportBinding) {
return;
}

/**
* Retrieves the deconstructed bindings from the Ember import, accounting for aliasing
* of the import.
*/
disallowedCalls = disallowedCalls.concat(
mergeDisallowedCalls(
collectObjectPatternBindings(node, {
[emberImportBinding]: ['run']
})
)
);
},

CallExpression(node) {
const caller = getCaller(node);

if (!disallowedCalls.includes(cleanCaller(caller))) {
return;
}

const normalizedArguments = normalizeArguments(caller, node.arguments);
const fnToRunOnce = getMethodToRunOnce(normalizedArguments);

// The fnToRunceOnce is a string it means that it will be resolved on the target at the time once or
// scheduleOnce is invoked.
if (isAnonymousFunction(fnToRunOnce) && !isString(fnToRunOnce)) {
context.report(node, MESSAGE);
}
}
};
}
};
Loading