Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

eslint-plugin-ember

Package Overview
Dependencies
Maintainers
5
Versions
189
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-ember - npm Package Compare versions

Comparing version 4.3.0 to 4.4.0

tests/__snapshots__/recommended.js.snap

4

docs/rules/order-in-components.md

@@ -17,3 +17,3 @@ ## Organize your components

'actions',
'method',
['method', 'empty-method'],
]

@@ -33,3 +33,3 @@ }]

'actions',
'method',
['method', 'empty-method'],
]

@@ -36,0 +36,0 @@ ```

@@ -18,3 +18,3 @@ ## Organize your controllers

'actions',
'method',
['method', 'empty-method'],
]

@@ -21,0 +21,0 @@ }]

@@ -13,6 +13,16 @@ ## Organize your routes

'property',
'single-line-function',
'multi-line-function',
'beforeModel',
'model',
'lifecycle-hook',
'afterModel',
'serialize',
'redirect',
'activate',
'setupController',
'renderTemplate',
'resetController',
'deactivate',
'actions',
'method',
['method', 'empty-method'],
]

@@ -29,5 +39,16 @@ }]

'model',
'lifecycle-hook',
[
'beforeModel',
'model',
'afterModel',
'serialize',
'redirect',
'activate',
'setupController',
'renderTemplate',
'resetController',
'deactivate'
],
'actions',
'method',
['method', 'empty-method'],
]

@@ -45,6 +66,8 @@ ```

3. Custom properties
4. model() hook
5. Other route's methods (beforeModel etc.)
6. Actions
7. Custom / private methods
4. beforeModel() hook
5. model() hook
6. afterModel() hook
7. Other lifecycle hooks in execution order (serialize, redirect, etc)
8. Actions
9. Custom / private methods

@@ -66,8 +89,3 @@ ```javascript

// 4. Model hook
model() {
return this.store.findAll('article');
},
// 5. Other route's methods
// 4. beforeModel hook
beforeModel() {

@@ -78,4 +96,21 @@ if (!get(this, 'currentUser.isAdmin')) {

},
// 5. model hook
model() {
return this.store.findAll('article');
},
// 6. afterModel hook
afterModel(articles) {
articles.forEach((article) => {
article.set('foo', 'bar');
});
},
// 6. All actions
// 7. Other route's methods
setupController(controller) {
controller.set('foo', 'bar');
},
// 8. All actions
actions: {

@@ -87,3 +122,3 @@ sneakyAction() {

// 7. Custom / private methods
// 9. Custom / private methods
_secretMethod() {

@@ -90,0 +125,0 @@ // custom secret method logic

'use strict';
const resolve = require('path').resolve;
const requireIndex = require('requireindex');
const requireFolderTree = require('require-folder-tree');
const rules = requireIndex(resolve(__dirname, 'rules'));
const configs = requireIndex(resolve(__dirname, 'config'));
const rules = requireFolderTree(resolve(__dirname, 'rules'));
const configs = requireFolderTree(resolve(__dirname, 'config'));

@@ -9,0 +9,0 @@ /* eslint-disable import/no-dynamic-require */

@@ -7,2 +7,3 @@ 'use strict';

const reportUnorderedProperties = propOrder.reportUnorderedProperties;
const addBackwardsPosition = propOrder.addBackwardsPosition;

@@ -17,3 +18,3 @@ const ORDER = [

'actions',
'method',
['method', 'empty-method'],
];

@@ -37,3 +38,4 @@

const options = context.options[0] || {};
const order = options.order || ORDER;
const order = options.order ? addBackwardsPosition(options.order, 'empty-method', 'method') : ORDER;
const filePath = context.getFilename();

@@ -40,0 +42,0 @@

@@ -7,2 +7,3 @@ 'use strict';

const reportUnorderedProperties = propOrder.reportUnorderedProperties;
const addBackwardsPosition = propOrder.addBackwardsPosition;

@@ -18,3 +19,3 @@ const ORDER = [

'actions',
'method',
['method', 'empty-method'],
];

@@ -38,4 +39,4 @@

const options = context.options[0] || {};
const order = options.order || ORDER;
const filePath = context.getFilename();
const order = options.order ? addBackwardsPosition(options.order, 'empty-method', 'method') : ORDER;

@@ -42,0 +43,0 @@ return {

@@ -7,2 +7,3 @@ 'use strict';

const reportUnorderedProperties = propOrder.reportUnorderedProperties;
const addBackwardsPosition = propOrder.addBackwardsPosition;

@@ -33,3 +34,3 @@ const ORDER = [

const options = context.options[0] || {};
const order = options.order || ORDER;
const order = options.order ? addBackwardsPosition(options.order, 'empty-method', 'method') : ORDER;

@@ -36,0 +37,0 @@ return {

@@ -7,2 +7,3 @@ 'use strict';

const reportUnorderedProperties = propOrder.reportUnorderedProperties;
const addBackwardsPosition = propOrder.addBackwardsPosition;

@@ -15,6 +16,14 @@ const ORDER = [

'multi-line-function',
'beforeModel',
'model',
'lifecycle-hook',
'afterModel',
'serialize',
'redirect',
'activate',
'setupController',
'renderTemplate',
'resetController',
'deactivate',
'actions',
'method',
['method', 'empty-method']
];

@@ -33,3 +42,3 @@

},
fixable: null, // or "code" or "whitespace"
fixable: null // or "code" or "whitespace"
},

@@ -39,3 +48,20 @@

const options = context.options[0] || {};
const order = options.order || ORDER;
let order = options.order ? addBackwardsPosition(options.order, 'empty-method', 'method') : ORDER;
order = order.slice(0);
const indexOfLifecycleHook = order.indexOf('lifecycle-hook');
if (indexOfLifecycleHook !== -1) {
order.splice(indexOfLifecycleHook, 1, [
'beforeModel',
'afterModel',
'serialize',
'redirect',
'activate',
'setupController',
'renderTemplate',
'resetController',
'deactivate'
]);
}
const filePath = context.getFilename();

@@ -48,5 +74,5 @@

reportUnorderedProperties(node, context, 'route', order);
},
}
};
}
};

@@ -120,2 +120,6 @@ 'use strict';

}
// Skip calls made on Ember methods
if (isIdentifier(callee.object) && callee.object.name === emberImportAliasName) {
return;
}

@@ -122,0 +126,0 @@ if (isIdentifier(method) && avoidedMethods.indexOf(method.name) > -1) {

@@ -30,3 +30,3 @@ 'use strict';

isActionsProp,
isModelProp,
isRouteLifecycleHook,

@@ -40,4 +40,2 @@ isRelation,

isRoute,
isRouteMethod,
isRouteDefaultMethod,
isRouteCustomFunction,

@@ -182,4 +180,5 @@ isRouteProperty,

function isModelProp(property) {
return property.key.name === 'model' && utils.isFunctionExpression(property.value);
function isRouteLifecycleHook(property) {
return isFunctionExpression(property.value) &&
isRouteLifecycleHookName(property.key.name);
}

@@ -224,60 +223,20 @@

function isRouteMethod(name) {
function isRouteLifecycleHookName(name) {
return [
'activate',
'addObserver',
'afterModel',
'beforeModel',
'cacheFor',
'controllerFor',
'create',
'deactivate',
'decrementProperty',
'destroy',
'disconnectOutlet',
'extend',
'get',
'getProperties',
'getWithDefault',
'has',
'incrementProperty',
'init',
'intermediateTransitionTo',
'model',
'modelFor',
'notifyPropertyChange',
'off',
'on',
'one',
'paramsFor',
'redirect',
'refresh',
'removeObserver',
'render',
'renderTemplate',
'reopen',
'reopenClass',
'replaceWith',
'resetController',
'send',
'serialize',
'set',
'setProperties',
'setupController',
'toString',
'toggleProperty',
'transitionTo',
'trigger',
'willDestroy',
'setupController'
].indexOf(name) > -1;
}
function isRouteDefaultMethod(property) {
return isFunctionExpression(property.value) &&
isRouteMethod(property.key.name);
}
function isRouteCustomFunction(property) {
return isFunctionExpression(property.value) &&
!isRouteMethod(property.key.name);
!isRouteLifecycleHookName(property.key.name);
}

@@ -284,0 +243,0 @@

'use strict';
const ember = require('./ember');
const utils = require('./utils');

@@ -8,2 +9,3 @@ module.exports = {

reportUnorderedProperties,
addBackwardsPosition
};

@@ -17,10 +19,20 @@

observer: 'observer',
beforeModel: 'lifecycle hook',
model: '"model" hook',
afterModel: 'lifecycle hook',
serialize: 'lifecycle hook',
redirect: 'lifecycle hook',
activate: 'lifecycle hook',
setupController: 'lifecycle hook',
renderTemplate: 'lifecycle hook',
resetController: 'lifecycle hook',
deactivate: 'lifecycle hook',
'lifecycle-hook': 'lifecycle hook',
actions: 'actions hash',
method: 'method',
'empty-method': 'empty method',
unknown: 'unknown property type',
attribute: 'attribute',
relationship: 'relationship',
'query-params': 'property',
'query-params': 'property'
};

@@ -58,6 +70,4 @@

return 'inherited-property';
} else if (ember.isModelProp(node)) {
return 'model';
} else if (ember.isRouteDefaultMethod(node)) {
return 'lifecycle-hook';
} else if (ember.isRouteLifecycleHook(node)) {
return node.key.name;
}

@@ -87,2 +97,6 @@ }

if (ember.isFunctionExpression(node.value)) {
if (utils.isEmptyMethod(node)) {
return 'empty-method';
}
return 'method';

@@ -114,3 +128,5 @@ }

let prefix;
if (!node.computed && type !== 'actions' && type !== 'model') {
if (!node.computed &&
type !== 'actions' &&
type !== 'model') {
if (node.key.type === 'Identifier') {

@@ -143,3 +159,3 @@ prefix = node.key.name;

node: property,
type,
type
};

@@ -172,1 +188,28 @@

}
function addBackwardsPosition(order, newPosition, targetPosition) {
const positionOrder = order.slice();
const containsPosition = positionOrder.some((position) => {
if (Array.isArray(position)) {
return position.indexOf(newPosition) > -1;
}
return position === newPosition;
});
if (!containsPosition) {
const targetIndex = positionOrder.indexOf(targetPosition);
if (targetIndex > -1) {
positionOrder[targetIndex] = [targetPosition, newPosition];
} else {
positionOrder.forEach((position) => {
if (Array.isArray(position) && position.indexOf(targetPosition) > -1) {
position.push(newPosition);
}
});
}
}
return positionOrder;
}

@@ -28,2 +28,3 @@ 'use strict';

collectObjectPatternBindings,
isEmptyMethod,
};

@@ -361,1 +362,13 @@

}
/**
* Check whether or not a node is a empty method.
*
* @param {Object} node The node to check.
* @returns {boolean} Whether or not the node is an empty method.
*/
function isEmptyMethod(node) {
return node.value.body
&& node.value.body.body
&& node.value.body.body.length <= 0;
}
{
"name": "eslint-plugin-ember",
"version": "4.3.0",
"version": "4.4.0",
"description": "Eslint plugin for Ember.js apps",

@@ -57,3 +57,3 @@ "main": "lib/index.js",

"ember-rfc176-data": "^0.2.7",
"requireindex": "^1.1.0",
"require-folder-tree": "^1.4.5",
"snake-case": "^2.1.0"

@@ -60,0 +60,0 @@ },

@@ -79,4 +79,5 @@ /**

* IMPORTANT!
* This file has been automatically generated,
* in order to update it's content execute "npm run update"
* This file has been automatically generated.
* In order to update its content based on rules'
* definitions, execute "npm run update"
*/

@@ -83,0 +84,0 @@ module.exports = ${JSON.stringify(recommendedRules, null, 2)}`;

@@ -357,2 +357,31 @@ // ------------------------------------------------------------------------------

parserOptions: { ecmaVersion: 6, sourceType: 'module' },
},
{
code: `export default Component.extend({
foo: computed(function() {
}).volatile(),
onFoo() {},
bar() { const foo = 'bar'},
onFoo: () => {}
});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
},
{
code: `export default Component.extend({
onFoo() {},
onFoo: () => {},
foo: computed(function() {
}).volatile(),
bar() { const foo = 'bar'}
});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
options: [{
order: [
'property',
'empty-method',
'single-line-function',
'multi-line-function',
'method',
],
}],
}

@@ -550,2 +579,3 @@ ],

customFunc() {
const foo = 'bar';
},

@@ -557,3 +587,3 @@ actions: {}

message: 'The actions hash should be above the "customFunc" method on line 2',
line: 4,
line: 5,
}],

@@ -560,0 +590,0 @@ },

@@ -25,4 +25,4 @@ // ------------------------------------------------------------------------------

actions: {},
_customAction() {},
_customAction2: function() {},
_customAction() { const foo = 'bar'; },
_customAction2: function() { const foo = 'bar'; },
tSomeTask: task(function* () {})

@@ -61,3 +61,3 @@ });`,

actions: {},
_customAction() {}
_customAction() { const foo = 'bar'; }
});`,

@@ -73,3 +73,3 @@ parserOptions: { ecmaVersion: 6, sourceType: 'module' },

}),
_customAction() {}
_customAction() { const foo = 'bar'; }
});`,

@@ -148,3 +148,3 @@ parserOptions: { ecmaVersion: 6, sourceType: 'module' },

queryParams: [],
_customAction() {},
_customAction() { const foo = 'bar'; },
actions: {}

@@ -151,0 +151,0 @@ });`,

@@ -17,3 +17,3 @@ // ------------------------------------------------------------------------------

code: 'export default Route.extend();',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
},

@@ -28,10 +28,18 @@ {

}),
beforeModel() {},
model() {},
beforeModel() {},
afterModel() {},
serialize() {},
redirect() {},
activate() {},
setupController() {},
renderTemplate() {},
resetController() {},
deactivate() {},
actions: {},
_customAction() {},
_customAction2: function() {},
_customAction() { const foo = 'bar'; },
_customAction2: function() { const foo = 'bar'; },
tSomeTask: task(function* () {})
});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
},

@@ -46,4 +54,5 @@ {

}),
beforeModel() {},
model() {},
beforeModel() {},
afterModel() {},
actions: {},

@@ -54,3 +63,3 @@ _customAction() {},

});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
},

@@ -65,5 +74,5 @@ {

},
_customAction() {}
_customAction() { const foo = 'bar'; }
});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
},

@@ -76,3 +85,3 @@ {

});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
},

@@ -88,3 +97,3 @@ {

});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
},

@@ -98,9 +107,25 @@ {

});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
},
{
code: `export default Route.extend({
model() {},
beforeModel() {},
currentUser: service(),
});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
options: [{
order: [
'model',
'lifecycle-hook',
'service'
]
}]
},
{
code: `export default Route.extend({
deactivate() {},
beforeModel() {},
model() {},
currentUser: service(),
model() {}
});`,

@@ -111,7 +136,28 @@ parserOptions: { ecmaVersion: 6, sourceType: 'module' },

'lifecycle-hook',
'model',
'service',
],
}],
'model'
]
}]
},
{
code: `export default Route.extend({
deactivate() {},
setupController() {},
beforeModel() {},
currentUser: service(),
model() {}
});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
options: [{
order: [
[
'deactivate',
'setupController',
'beforeModel'
],
'service',
'model'
]
}]
}
],

@@ -124,4 +170,4 @@ invalid: [

customProp: "test",
beforeModel() {},
model() {},
beforeModel() {},
vehicle: alias("car"),

@@ -134,7 +180,7 @@ actions: {},

message: 'The "currentUser" service injection should be above the inherited "queryParams" property on line 2',
line: 3,
line: 3
}, {
message: 'The "vehicle" single-line function should be above the "model" hook on line 5',
line: 7,
}],
message: 'The "vehicle" single-line function should be above the "beforeModel" lifecycle hook on line 5',
line: 7
}]
},

@@ -146,4 +192,4 @@ {

customProp: "test",
beforeModel() {},
model() {},
beforeModel() {},
vehicle: alias("car"),

@@ -156,7 +202,7 @@ actions: {},

message: 'The "currentUser" service injection should be above the inherited "queryParams" property on line 2',
line: 3,
line: 3
}, {
message: 'The "vehicle" single-line function should be above the "model" hook on line 5',
line: 7,
}],
message: 'The "vehicle" single-line function should be above the "beforeModel" lifecycle hook on line 5',
line: 7
}]
},

@@ -167,4 +213,4 @@ {

queryParams: {},
beforeModel() {},
model() {},
beforeModel() {},
actions: {},

@@ -178,7 +224,7 @@ _customAction() {},

message: 'The inherited "queryParams" property should be above the "customProp" property on line 2',
line: 3,
line: 3
}, {
message: 'The "levelOfHappiness" multi-line function should be above the "model" hook on line 4',
line: 8,
}],
message: 'The "levelOfHappiness" multi-line function should be above the "beforeModel" lifecycle hook on line 4',
line: 8
}]
},

@@ -189,4 +235,4 @@ {

queryParams: {},
model() {},
beforeModel() {},
model() {},
actions: {},

@@ -198,7 +244,7 @@ _customAction() {}

message: 'The inherited "queryParams" property should be above the "customProp" property on line 2',
line: 3,
line: 3
}, {
message: 'The "model" hook should be above the "beforeModel" lifecycle hook on line 4',
line: 5,
}],
message: 'The "beforeModel" lifecycle hook should be above the "model" hook on line 4',
line: 5
}]
},

@@ -211,3 +257,3 @@ {

model() {},
_customAction() {},
_customAction() { const foo = 'bar'; },
actions: {}

@@ -218,7 +264,7 @@ });`,

message: 'The "customProp" property should be above the "vehicle" single-line function on line 3',
line: 4,
line: 4
}, {
message: 'The actions hash should be above the "_customAction" method on line 6',
line: 7,
}],
line: 7
}]
},

@@ -234,4 +280,4 @@ {

message: 'The "customProp" property should be above the "model" hook on line 2',
line: 3,
}],
line: 3
}]
},

@@ -247,9 +293,50 @@ {

message: 'The inherited "mergedProperties" property should be above the "test" property on line 2',
line: 3,
}],
line: 3
}]
},
{
code: `export default Route.extend({
currentUser: service(),
queryParams: {},
customProp: "test",
vehicle: alias("car"),
levelOfHappiness: computed("attitude", "health", () => {
}),
beforeModel() {},
model() {},
afterModel() {},
setupController() {},
redirect() {},
serialize() {},
activate() {},
deactivate() {},
renderTemplate() {},
resetController() {},
actions: {},
_customAction() {},
_customAction2: function() {},
tSomeTask: task(function* () {})
});`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
errors: [{
message: 'The "redirect" lifecycle hook should be above the "setupController" lifecycle hook on line 11',
line: 12
}, {
message: 'The "serialize" lifecycle hook should be above the "setupController" lifecycle hook on line 11',
line: 13
}, {
message: 'The "activate" lifecycle hook should be above the "setupController" lifecycle hook on line 11',
line: 14
}, {
message: 'The "renderTemplate" lifecycle hook should be above the "deactivate" lifecycle hook on line 15',
line: 16
}, {
message: 'The "resetController" lifecycle hook should be above the "deactivate" lifecycle hook on line 15',
line: 17
}]
},
{
code: `export default Route.extend({
test: "asd",
_test2() {},
_test2() { const foo = 'bar'; },
model() {}

@@ -260,4 +347,4 @@ });`,

message: 'The "model" hook should be above the "_test2" method on line 3',
line: 4,
}],
line: 4
}]
},

@@ -273,4 +360,4 @@ {

message: 'The "test" property should be above the "model" hook on line 2',
line: 3,
}],
line: 3
}]
},

@@ -286,4 +373,4 @@ {

message: 'The "test" property should be above the "model" hook on line 2',
line: 3,
}],
line: 3
}]
},

@@ -299,6 +386,6 @@ {

message: 'The "test" property should be above the "model" hook on line 2',
line: 3,
}],
},
],
line: 3
}]
}
]
});

@@ -17,4 +17,4 @@ // ------------------------------------------------------------------------------

'get(controller, "test")',
'set(this, "test")',
'set(controller, "test")',
'set(this, "test", someValue)',
'set(controller, "test", someValue)',
'getProperties(this, name, email, password)',

@@ -38,2 +38,14 @@ 'getProperties(controller, name, email, password)',

},
{
code: 'import Ember from "ember"; Ember.get(this, "test")',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
},
{
code: 'import Ember from "ember"; Ember.set(this, "test", someValue)',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
},
{
code: 'import EmberAlias from "ember"; EmberAlias.get(this, "test")',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
},
],

@@ -40,0 +52,0 @@ invalid: [

@@ -330,11 +330,35 @@ 'use strict';

describe('isModelProp', () => {
describe('isRouteLifecycleHook', () => {
let node;
it('should be a model prop', () => {
it('should be a route lifecycle hook', () => {
node = getProperty('test = { beforeModel() {} }');
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
node = getProperty('test = { model() {} }');
expect(emberUtils.isModelProp(node)).toBeTruthy();
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
node = getProperty('test = { model: function() {} }');
expect(emberUtils.isModelProp(node)).toBeTruthy();
node = getProperty('test = { afterModel() {} }');
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
node = getProperty('test = { serialize() {} }');
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
node = getProperty('test = { redirect() {} }');
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
node = getProperty('test = { activate() {} }');
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
node = getProperty('test = { setupController() {} }');
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
node = getProperty('test = { renderTemplate() {} }');
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
node = getProperty('test = { resetController() {} }');
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
node = getProperty('test = { deactivate() {} }');
expect(emberUtils.isRouteLifecycleHook(node)).toBeTruthy();
});

@@ -341,0 +365,0 @@ });

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc