diff --git a/lib/rules/alias-model-in-controller.js b/lib/rules/alias-model-in-controller.js index 4c0bea9b5b..afe4a0f31f 100644 --- a/lib/rules/alias-model-in-controller.js +++ b/lib/rules/alias-model-in-controller.js @@ -29,7 +29,9 @@ module.exports = { }; return { - CallExpression(node) { + 'CallExpression > MemberExpression[property.name="extend"]'(memberExpressionNode) { + const node = memberExpressionNode.parent; + if (!ember.isEmberController(context, node)) { return; } diff --git a/lib/rules/avoid-using-needs-in-controllers.js b/lib/rules/avoid-using-needs-in-controllers.js index 1066fd9f4f..de4a9846d2 100644 --- a/lib/rules/avoid-using-needs-in-controllers.js +++ b/lib/rules/avoid-using-needs-in-controllers.js @@ -27,22 +27,27 @@ module.exports = { context.report(node, message); }; - return { - CallExpression(node) { - const isReopenNode = ember.isReopenObject(node) || ember.isReopenClassObject(node); + function checkMemberExpression(memberExpressionNode) { + const node = memberExpressionNode.parent; - if (!ember.isEmberController(context, node) && !isReopenNode) { - return; - } + if (!ember.isEmberController(context, node)) { + return; + } - const properties = ember.getModuleProperties(node); + const properties = ember.getModuleProperties(node); - properties.forEach(property => { - if (property.key.name === 'needs') { - report(property); - } - }); - }, + properties.forEach(property => { + if (property.key.name === 'needs') { + report(property); + } + }); + } + + return { + 'CallExpression > MemberExpression[property.name="extend"]': checkMemberExpression, + 'CallExpression > MemberExpression[property.name="reopen"]': checkMemberExpression, + 'CallExpression > MemberExpression[property.name="reopenClass"]': checkMemberExpression, + 'CallExpression > MemberExpression[property.value="extend"]': checkMemberExpression, }; }, }; diff --git a/lib/rules/new-module-imports.js b/lib/rules/new-module-imports.js index 017783ced2..a94d2d467b 100644 --- a/lib/rules/new-module-imports.js +++ b/lib/rules/new-module-imports.js @@ -2,7 +2,7 @@ const MAPPING = require('ember-rfc176-data'); const { buildMessage, getFullNames, isDestructuring } = require('../utils/new-module'); -const { getSourceModuleNameForIdentifier } = require('../utils/utils'); +const { getSourceModuleNameForIdentifier } = require('../utils/import-info'); const GLOBALS = MAPPING.reduce((memo, exportDefinition) => { if (exportDefinition.deprecated) { diff --git a/lib/rules/no-actions-hash.js b/lib/rules/no-actions-hash.js index d1a0cf44ca..7dffbfb240 100644 --- a/lib/rules/no-actions-hash.js +++ b/lib/rules/no-actions-hash.js @@ -41,7 +41,9 @@ module.exports = { reportActionsProp(utils.findNodes(node.body.body, 'ClassProperty')); } }, - CallExpression(node) { + 'CallExpression > MemberExpression[property.name="extend"]'(memberExpressionNode) { + const node = memberExpressionNode.parent; + if (inClassWhichCanContainActions(context, node)) { reportActionsProp(ember.getModuleProperties(node)); } diff --git a/lib/rules/no-classic-classes.js b/lib/rules/no-classic-classes.js index 6be70cc511..cfb641a435 100644 --- a/lib/rules/no-classic-classes.js +++ b/lib/rules/no-classic-classes.js @@ -1,6 +1,6 @@ 'use strict'; -const { getSourceModuleNameForIdentifier } = require('../utils/utils'); +const { getSourceModuleNameForIdentifier } = require('../utils/import-info'); const { isObjectExpression } = require('../utils/types'); const ERROR_MESSAGE_NO_CLASSIC_CLASSES = diff --git a/lib/rules/no-get.js b/lib/rules/no-get.js index 2d1eb447d2..9aa6e409c5 100644 --- a/lib/rules/no-get.js +++ b/lib/rules/no-get.js @@ -84,10 +84,13 @@ module.exports = { // Check for situations which the rule should ignore. // ************************** - if (emberUtils.isEmberProxy(context, node)) { + if (emberUtils.isEmberObject(node) && emberUtils.isEmberProxy(context, node)) { currentProxyObject = node; // Keep track of being inside a proxy object. } - if (emberUtils.isEmberObjectImplementingUnknownProperty(node)) { + if ( + emberUtils.isEmberObject(node) && + emberUtils.isEmberObjectImplementingUnknownProperty(node) + ) { currentClassWithUnknownPropertyMethod = node; } if (currentProxyObject || currentClassWithUnknownPropertyMethod) { diff --git a/lib/rules/no-new-mixins.js b/lib/rules/no-new-mixins.js index 97c38bb45f..9cc0a10d1a 100644 --- a/lib/rules/no-new-mixins.js +++ b/lib/rules/no-new-mixins.js @@ -26,7 +26,9 @@ module.exports = { create(context) { return { - CallExpression(node) { + 'CallExpression > MemberExpression[property.name="create"]'(memberExpressionNode) { + const node = memberExpressionNode.parent; + if (ember.isEmberMixin(context, node)) { context.report(node, ERROR_MESSAGE); } diff --git a/lib/rules/no-on-calls-in-components.js b/lib/rules/no-on-calls-in-components.js index 2274ce6bbf..1d0459618d 100644 --- a/lib/rules/no-on-calls-in-components.js +++ b/lib/rules/no-on-calls-in-components.js @@ -63,7 +63,9 @@ module.exports = { }; return { - CallExpression(node) { + 'CallExpression > MemberExpression[property.name="extend"]'(memberExpressionNode) { + const node = memberExpressionNode.parent; + if (!ember.isEmberComponent(context, node)) { return; } diff --git a/lib/rules/order-in-components.js b/lib/rules/order-in-components.js index d0ad40088d..410f1a194b 100644 --- a/lib/rules/order-in-components.js +++ b/lib/rules/order-in-components.js @@ -84,7 +84,9 @@ module.exports = { } return { - CallExpression(node) { + 'CallExpression > MemberExpression[property.name="extend"]'(memberExpressionNode) { + const node = memberExpressionNode.parent; + if (!ember.isEmberComponent(context, node)) { return; } diff --git a/lib/rules/order-in-controllers.js b/lib/rules/order-in-controllers.js index 532d22b98f..77aa2b8bec 100644 --- a/lib/rules/order-in-controllers.js +++ b/lib/rules/order-in-controllers.js @@ -56,7 +56,9 @@ module.exports = { : ORDER; return { - CallExpression(node) { + 'CallExpression > MemberExpression[property.name="extend"]'(memberExpressionNode) { + const node = memberExpressionNode.parent; + if (!ember.isEmberController(context, node)) { return; } diff --git a/lib/rules/order-in-models.js b/lib/rules/order-in-models.js index 491c247d19..809ad57b55 100644 --- a/lib/rules/order-in-models.js +++ b/lib/rules/order-in-models.js @@ -46,7 +46,9 @@ module.exports = { const filePath = context.getFilename(); return { - CallExpression(node) { + 'CallExpression > MemberExpression[property.name="extend"]'(memberExpressionNode) { + const node = memberExpressionNode.parent; + if (!ember.isDSModel(node, filePath)) { return; } diff --git a/lib/rules/order-in-routes.js b/lib/rules/order-in-routes.js index 6a9064a61e..a1536fb833 100644 --- a/lib/rules/order-in-routes.js +++ b/lib/rules/order-in-routes.js @@ -79,7 +79,9 @@ module.exports = { } return { - CallExpression(node) { + 'CallExpression > MemberExpression[property.name="extend"]'(memberExpressionNode) { + const node = memberExpressionNode.parent; + if (!ember.isEmberRoute(context, node)) { return; } diff --git a/lib/rules/require-super-in-init.js b/lib/rules/require-super-in-init.js index 4592dd5b89..2edf4e80a2 100644 --- a/lib/rules/require-super-in-init.js +++ b/lib/rules/require-super-in-init.js @@ -88,7 +88,9 @@ module.exports = { }; return { - CallExpression(node) { + 'CallExpression > MemberExpression[property.name="extend"]'(memberExpressionNode) { + const node = memberExpressionNode.parent; + if ( !ember.isEmberComponent(context, node) && !ember.isEmberController(context, node) && diff --git a/lib/rules/require-tagless-components.js b/lib/rules/require-tagless-components.js index 4dc7847135..8103cb4e7c 100644 --- a/lib/rules/require-tagless-components.js +++ b/lib/rules/require-tagless-components.js @@ -1,7 +1,7 @@ 'use strict'; const { isEmberComponent } = require('../utils/ember'); -const { getSourceModuleNameForIdentifier } = require('../utils/utils'); +const { getSourceModuleNameForIdentifier } = require('../utils/import-info'); const { isCallExpression, isIdentifier, diff --git a/lib/rules/use-ember-data-rfc-395-imports.js b/lib/rules/use-ember-data-rfc-395-imports.js index 3d033cf5a9..6e23640c97 100644 --- a/lib/rules/use-ember-data-rfc-395-imports.js +++ b/lib/rules/use-ember-data-rfc-395-imports.js @@ -2,7 +2,7 @@ const MAPPINGS = require('@ember-data/rfc395-data'); const { buildFix, buildMessage, getFullNames, isDestructuring } = require('../utils/new-module'); -const { getSourceModuleNameForIdentifier } = require('../utils/utils'); +const { getSourceModuleNameForIdentifier } = require('../utils/import-info'); /** * This function returns an object like this: diff --git a/lib/utils/ember.js b/lib/utils/ember.js index c417c389d1..ab86e0a71a 100644 --- a/lib/utils/ember.js +++ b/lib/utils/ember.js @@ -1,5 +1,6 @@ 'use strict'; +const { getSourceModuleNameForIdentifier, isDefaultImport } = require('./import-info'); const utils = require('./utils'); const types = require('./types'); const assert = require('assert'); @@ -70,17 +71,6 @@ const CORE_MODULE_IMPORT_PATHS = { ObjectProxy: '@ember/object/proxy', }; -function isClassicEmberCoreModule(node, module, filePath) { - const isExtended = isEmberObject(node); - let isModuleByPath; - - if (filePath) { - isModuleByPath = isModuleByFilePath(filePath, module.toLowerCase()) && isExtended; - } - - return isModule(node, module) || isModuleByPath; -} - function isLocalModule(callee, element) { return ( (types.isIdentifier(callee) && callee.name === element) || @@ -169,26 +159,41 @@ function isReopenObject(node) { } function isEmberCoreModule(context, node, moduleName) { + // Handle Ember.X references to classes + if ( + types.isCallExpression(node) && + types.isMemberExpression(node.callee) && + types.isMemberExpression(node.callee.object) && + utils.getSourceModuleName(node.callee) === 'Ember' + ) { + return node.callee.object.property.name === moduleName; + } + + let superClass; + if (types.isCallExpression(node)) { // "classic" class pattern - return isClassicEmberCoreModule(node, moduleName, context.getFilename()); + superClass = node.callee.object; } else if (types.isClassDeclaration(node)) { // native classes - if (!node.superClass) { - return false; - } - const superClassImportPath = utils.getSourceModuleNameForIdentifier(context, node.superClass); - - if (superClassImportPath === CORE_MODULE_IMPORT_PATHS[moduleName]) { - return true; - } + superClass = node.superClass; } else { assert( false, 'Function should only be called on a `CallExpression` (classic class) or `ClassDeclaration` (native class)' ); } - return false; + + if (!superClass) { + return false; + } + + const superClassImportPath = getSourceModuleNameForIdentifier(context, superClass); + + return ( + superClassImportPath === CORE_MODULE_IMPORT_PATHS[moduleName] && + isDefaultImport(context, superClass) + ); } function isEmberComponent(context, node) { diff --git a/lib/utils/import-info.js b/lib/utils/import-info.js new file mode 100644 index 0000000000..1f7daacec6 --- /dev/null +++ b/lib/utils/import-info.js @@ -0,0 +1,66 @@ +'use strict'; + +const { isImportDeclaration, isImportDefaultSpecifier } = require('./types'); +const { getSourceModuleName } = require('./utils'); + +module.exports = { + getSourceModuleNameForIdentifier, + isDefaultImport, +}; + +/** + * Gets the ImportDeclaration node that an identifier was imported from + * if it was imported + * + * @param {Object} context the context of the ESLint rule + * @param {node} node the Idenfifier to find an import for + * @returns {ImportDeclaration | undefined} The ImportDeclaration of the module the identifier was imported from, if it was imported + */ +function getImportDeclarationNode(context, node) { + const [program] = context.getAncestors(node); + + return program.body + .filter(isImportDeclaration) + .find(importDeclaration => + importDeclaration.specifiers.some( + specifier => specifier.local.name === getSourceModuleName(node) + ) + ); +} + +function getImportSpecifierNode(context, node) { + const importDeclaration = getImportDeclarationNode(context, node); + + return importDeclaration + ? importDeclaration.specifiers.find( + specifier => specifier.local.name === getSourceModuleName(node) + ) + : undefined; +} + +/** + * Gets the name of the module that an identifier was imported from, + * if it was imported + * + * @param {Object} context the context of the ESLint rule + * @param {node} node the Idenfifier to find an import for + * @returns {string | undefined} The name of the module the identifier was imported from, if it was imported + */ +function getSourceModuleNameForIdentifier(context, node) { + const importDeclaration = getImportDeclarationNode(context, node); + + return importDeclaration ? importDeclaration.source.value : undefined; +} + +/** + * Determines whether the given Identifer was the default import from some module + * + * @param {Object} context the context of the ESLint rule + * @param {node} node the Idenfifier to check + * @returns {boolean} Whether or not the identifier is a default import from a module + */ +function isDefaultImport(context, node) { + const importSpecifier = getImportSpecifierNode(context, node); + + return isImportDefaultSpecifier(importSpecifier); +} diff --git a/lib/utils/types.js b/lib/utils/types.js index 30886530e1..07c31e14ba 100644 --- a/lib/utils/types.js +++ b/lib/utils/types.js @@ -18,6 +18,7 @@ module.exports = { isFunctionExpression, isIdentifier, isImportDeclaration, + isImportDefaultSpecifier, isLiteral, isLogicalExpression, isMemberExpression, @@ -225,6 +226,16 @@ function isImportDeclaration(node) { return node !== undefined && node.type === 'ImportDeclaration'; } +/** + * Check whether or not a node is an ImportDefaultSpecifier. + * + * @param {Object} node The node to check. + * @returns {boolean} Whether or not the node is an ImportDefaultSpecifier. + */ +function isImportDefaultSpecifier(node) { + return node !== undefined && node.type === 'ImportDefaultSpecifier'; +} + /** * Check whether or not a node is an Literal. * diff --git a/lib/utils/utils.js b/lib/utils/utils.js index 10aecd985f..8f4831dba4 100644 --- a/lib/utils/utils.js +++ b/lib/utils/utils.js @@ -3,7 +3,6 @@ const { isCallExpression, isIdentifier, - isImportDeclaration, isLiteral, isMemberExpression, isNewExpression, @@ -19,7 +18,6 @@ module.exports = { getPropertyValue, getSize, getSourceModuleName, - getSourceModuleNameForIdentifier, isEmptyMethod, isGlobalCallExpression, parseArgs, @@ -202,27 +200,6 @@ function isEmptyMethod(node) { return node.value.body && node.value.body.body && node.value.body.body.length <= 0; } -/** - * Gets the name of the module that an identifier was imported from, - * if it was imported - * - * @param {Object} context the context of the ESLint rule - * @param {node} node the Idenfifier to find an import for - * @returns {string | undefined} The name of the module the identifier was imported from, if it was imported - */ -function getSourceModuleNameForIdentifier(context, node) { - const [program] = context.getAncestors(node); - const importDeclaration = program.body - .filter(isImportDeclaration) - .find(importDeclaration => - importDeclaration.specifiers.some( - specifier => specifier.local.name === getSourceModuleName(node) - ) - ); - - return importDeclaration ? importDeclaration.source.value : undefined; -} - function getSourceModuleName(node) { if (isMemberExpression(node) && node.object) { return getSourceModuleName(node.object); diff --git a/tests/lib/rules/alias-model-in-controller.js b/tests/lib/rules/alias-model-in-controller.js index c139632b2e..6eb5a49526 100644 --- a/tests/lib/rules/alias-model-in-controller.js +++ b/tests/lib/rules/alias-model-in-controller.js @@ -108,7 +108,10 @@ eslintTester.run('alias-model-in-controller', rule, { }, { filename: 'example-app/controllers/path/to/some-feature.js', - code: 'export default CustomController.extend({});', + code: ` + import CustomController from '@ember/controller'; + export default CustomController.extend({}); + `, output: null, errors: [ { @@ -118,7 +121,10 @@ eslintTester.run('alias-model-in-controller', rule, { }, { filename: 'example-app/some-feature/controller.js', - code: 'export default CustomController.extend({});', + code: ` + import CustomController from '@ember/controller'; + export default CustomController.extend({}); + `, output: null, errors: [ { @@ -128,7 +134,10 @@ eslintTester.run('alias-model-in-controller', rule, { }, { filename: 'example-app/twisted-path/some-file.js', - code: 'export default Controller.extend({});', + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({}); + `, output: null, errors: [ { diff --git a/tests/lib/rules/avoid-using-needs-in-controllers.js b/tests/lib/rules/avoid-using-needs-in-controllers.js index 1ffc98db0a..52a4e59673 100644 --- a/tests/lib/rules/avoid-using-needs-in-controllers.js +++ b/tests/lib/rules/avoid-using-needs-in-controllers.js @@ -17,16 +17,37 @@ const eslintTester = new RuleTester({ }); eslintTester.run('avoid-using-needs-in-controllers', rule, { valid: [ - 'export default Controller.extend();', - 'export default FooController.extend();', - 'Controller.reopen();', - 'FooController.reopen();', - 'Controller.reopenClass();', - 'FooController.reopenClass();', + ` + import Controller from '@ember/controller'; + export default Controller.extend(); + `, + ` + import FooController from '@ember/controller'; + export default FooController.extend(); + `, + ` + import Controller from '@ember/controller'; + Controller.reopen(); + `, + ` + import FooController from '@ember/controller'; + FooController.reopen(); + `, + ` + import Controller from '@ember/controller'; + Controller.reopenClass(); + `, + ` + import FooController from '@ember/controller'; + FooController.reopenClass(); + `, ], invalid: [ { - code: 'export default Controller.extend({ needs: [] });', + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ needs: [] }); + `, output: null, errors: [ { @@ -36,7 +57,10 @@ eslintTester.run('avoid-using-needs-in-controllers', rule, { ], }, { - code: 'Controller.reopenClass({ needs: [] });', + code: ` + import Controller from '@ember/controller'; + Controller.reopenClass({ needs: [] }); + `, output: null, errors: [ { @@ -46,7 +70,10 @@ eslintTester.run('avoid-using-needs-in-controllers', rule, { ], }, { - code: 'Controller.reopen({ needs: [] });', + code: ` + import Controller from '@ember/controller'; + Controller.reopen({ needs: [] }); + `, output: null, errors: [ { @@ -56,7 +83,10 @@ eslintTester.run('avoid-using-needs-in-controllers', rule, { ], }, { - code: "export default Controller['extend']({ needs: [] });", + code: ` + import Controller from '@ember/controller'; + export default Controller['extend']({ needs: [] }); + `, output: null, errors: [ { @@ -67,7 +97,10 @@ eslintTester.run('avoid-using-needs-in-controllers', rule, { }, { filename: 'example-app/controllers/some-controller.js', - code: 'export default FooController.extend({ needs: [] });', + code: ` + import FooController from '@ember/controller'; + export default FooController.extend({ needs: [] }); + `, output: null, errors: [ { @@ -78,7 +111,10 @@ eslintTester.run('avoid-using-needs-in-controllers', rule, { }, { filename: 'example-app/controllers/some-controller.js', - code: 'FooController.reopenClass({ needs: [] });', + code: ` + import FooController from '@ember/controller'; + FooController.reopenClass({ needs: [] }); + `, output: null, errors: [ { @@ -89,7 +125,10 @@ eslintTester.run('avoid-using-needs-in-controllers', rule, { }, { filename: 'example-app/controllers/some-controller.js', - code: 'FooController.reopen({ needs: [] });', + code: ` + import FooController from '@ember/controller'; + FooController.reopen({ needs: [] }); + `, output: null, errors: [ { @@ -100,7 +139,10 @@ eslintTester.run('avoid-using-needs-in-controllers', rule, { }, { filename: 'example-app/controllers/some-controller.js', - code: "export default FooController['extend']({ needs: [] });", + code: ` + import FooController from '@ember/controller'; + export default FooController['extend']({ needs: [] }); + `, output: null, errors: [ { diff --git a/tests/lib/rules/no-actions-hash.js b/tests/lib/rules/no-actions-hash.js index eece3e3c52..1b4c743eda 100644 --- a/tests/lib/rules/no-actions-hash.js +++ b/tests/lib/rules/no-actions-hash.js @@ -18,33 +18,39 @@ const ruleTester = new RuleTester({ ruleTester.run('no-actions-hash', rule, { valid: [ ` + import Component from '@ember/component'; export default Component.extend({ foo: action(function() {}) }); `, ` + import Component from '@ember/component'; export default class MyComponent extends Component { @action foo() {} } `, ` + import Controller from '@ember/controller'; export default Controller.extend({ foo: action(function() {}) }); `, ` + import Controller from '@ember/controller'; export default class MyController extends Controller { @action foo() {} } `, ` + import Route from '@ember/routing/route'; export default Route.extend({ foo: action(function() {}) }); `, ` + import Route from '@ember/routing/route'; export default class MyRoute extends Route { @action foo() {} @@ -59,6 +65,7 @@ ruleTester.run('no-actions-hash', rule, { } `, ` + import Service from '@ember/service'; export default Service.extend({ actions: { }, @@ -69,6 +76,7 @@ ruleTester.run('no-actions-hash', rule, { invalid: [ { code: ` + import Component from '@ember/component'; export default Component.extend({ actions: { }, @@ -90,6 +98,7 @@ ruleTester.run('no-actions-hash', rule, { }, { code: ` + import Controller from '@ember/controller'; export default Controller.extend({ actions: { }, @@ -111,6 +120,7 @@ ruleTester.run('no-actions-hash', rule, { }, { code: ` + import Route from '@ember/routing/route'; export default Route.extend({ actions: { }, diff --git a/tests/lib/rules/no-new-mixins.js b/tests/lib/rules/no-new-mixins.js index 9f9b69c12a..00cffb2b3a 100644 --- a/tests/lib/rules/no-new-mixins.js +++ b/tests/lib/rules/no-new-mixins.js @@ -16,10 +16,13 @@ const eslintTester = new RuleTester({ eslintTester.run('no-new-mixins', rule, { valid: [ ` - import mixin from "some/addon"; - export default mixin; - `, - 'export default mixin.create({actions: {},});', + import mixin from "some/addon"; + export default mixin; + `, + ` + import mixin from 'some/addon'; + export default mixin.create(); + `, ], invalid: [ { diff --git a/tests/lib/rules/no-on-calls-in-components.js b/tests/lib/rules/no-on-calls-in-components.js index 29464f3fd2..08b07d0ca0 100644 --- a/tests/lib/rules/no-on-calls-in-components.js +++ b/tests/lib/rules/no-on-calls-in-components.js @@ -17,66 +17,170 @@ const message = "Don't use .on() for component lifecycle events."; eslintTester.run('no-on-calls-in-components', rule, { valid: [ - 'export default Component.extend();', - 'export default Component.extend({actions: {}});', - 'export default Component.extend({abc: service()});', - 'export default Component.extend({abc: inject.service()});', - 'export default Component.extend({abc: false});', - 'export default Component.extend({classNames: ["abc", "def"]});', - 'export default Component.extend({abc: computed(function () {})});', - 'export default Component.extend({abc: observer("abc", function () {})});', - 'export default Component.extend({abc: observer("abc", function () {test.on("xyz", def)})});', - 'export default Component.extend({abc: function () {test.on("xyz", def)}});', - 'export default Component.extend({abc() {$("body").on("click", def)}});', - 'export default Component.extend({didInsertElement() {$("body").on("click", def).on("click", function () {})}});', - 'export default Component.extend({actions: {abc() {test.on("xyz", def)}}});', - 'export default Component.extend({actions: {abc() {$("body").on("click", def).on("click", function () {})}}});', - 'export default Component.extend({abc: on("nonLifecycleEvent", function() {})});', + ` + import Component from '@ember/component'; + export default Component.extend(); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + actions: {} + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + abc: service() + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + abc: inject.service() + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + abc: false + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + classNames: ["abc", "def"] + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + abc: computed(function () {}) + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + abc: observer("abc", function () {}) + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + abc: observer("abc", function () { + test.on("xyz", def) + }) + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + abc: function () { + test.on("xyz", def) + } + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + abc() { + $("body").on("click", def) + } + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + didInsertElement() { + $("body").on("click", def).on("click", function () {}) + } + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + actions: { + abc() { + test.on("xyz", def) + } + } + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + actions: { + abc() { + $("body").on("click", def).on("click", function () {}) + } + } + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ + abc: on("nonLifecycleEvent", function() {}) + }); + `, { code: ` - let foo = { bar: 'baz' }; + import Component from '@ember/component'; - export default Component.extend({ - ...foo, - }); + let foo = { bar: 'baz' }; + + export default Component.extend({ + ...foo, + }); `, parserOptions: { ecmaVersion: 9, sourceType: 'module' }, }, ], invalid: [ { - code: `export default Component.extend({ - test: on("didInsertElement", function () {}) - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + test: on("didInsertElement", function () {}) + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Component.extend({ - test: on("init", observer("someProperty", function () { - return true; - })), - someComputedProperty: computed.bool(true) - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + test: on("init", observer("someProperty", function () { + return true; + })), + someComputedProperty: computed.bool(true) + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Component.extend({ - test: Ember.on("didInsertElement", function () {}), - someComputedProperty: Ember.computed.readOnly('Hello World!'), - anotherTest: Ember.on("willDestroyElement", function () {}) - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + test: Ember.on("didInsertElement", function () {}), + someComputedProperty: Ember.computed.readOnly('Hello World!'), + anotherTest: Ember.on("willDestroyElement", function () {}) + }); + `, output: null, errors: [ - { message, line: 2 }, { message, line: 4 }, + { message, line: 6 }, ], }, { filename: 'example-app/components/some-component/component.js', - code: - 'export default CustomComponent.extend({test: on("didInsertElement", function () {})});', + code: ` + import CustomComponent from '@ember/component'; + export default CustomComponent.extend({ + test: on("didInsertElement", function () {}) + }); + `, output: null, errors: [ { @@ -86,8 +190,12 @@ eslintTester.run('no-on-calls-in-components', rule, { }, { filename: 'example-app/components/some-component.js', - code: - 'export default CustomComponent.extend({test: on("didInsertElement", function () {})});', + code: ` + import CustomComponent from '@ember/component'; + export default CustomComponent.extend({ + test: on("didInsertElement", function () {}) + }); + `, output: null, errors: [ { @@ -97,7 +205,12 @@ eslintTester.run('no-on-calls-in-components', rule, { }, { filename: 'example-app/twised-path/some-file.js', - code: 'export default Component.extend({test: on("didInsertElement", function () {})});', + code: ` + import Component from '@ember/component'; + export default Component.extend({ + test: on("didInsertElement", function () {}) + }); + `, output: null, errors: [ { diff --git a/tests/lib/rules/order-in-components.js b/tests/lib/rules/order-in-components.js index a7997bf7c5..005bd3533f 100644 --- a/tests/lib/rules/order-in-components.js +++ b/tests/lib/rules/order-in-components.js @@ -17,8 +17,13 @@ const eslintTester = new RuleTester({ eslintTester.run('order-in-components', rule, { valid: [ - 'export default Component.extend();', - `export default Component.extend({ + ` + import Component from '@ember/component'; + export default Component.extend(); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ role: "sloth", vehicle: alias("car"), @@ -27,34 +32,49 @@ eslintTester.run('order-in-components', rule, { }), actions: {} - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ role: "sloth", levelOfHappiness: computed("attitude", "health", () => { }), actions: {} - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ levelOfHappiness: computed("attitude", "health", () => { }), actions: {} - });`, - `export default Component.extend(TestMixin, { + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend(TestMixin, { levelOfHappiness: computed("attitude", "health", () => { }), actions: {} - });`, - `export default Component.extend(TestMixin, TestMixin2, { + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend(TestMixin, TestMixin2, { levelOfHappiness: computed("attitude", "health", () => { }), actions: {} - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ abc: Ember.inject.service(), def: inject.service(), ghi: service(), @@ -63,28 +83,35 @@ eslintTester.run('order-in-components', rule, { levelOfHappiness: computed("attitude", "health", () => { }) - });`, + }); + `, ` - import { inject } from '@ember/service'; - export default Component.extend({ - abc: inject(), - def: inject.service(), - ghi: service(), + import Component from '@ember/component'; + import { inject } from '@ember/service'; + export default Component.extend({ + abc: inject(), + def: inject.service(), + ghi: service(), - role: "sloth", + role: "sloth", - levelOfHappiness: computed("attitude", "health", () => { - }) - }); - `, - `export default Component.extend({ + levelOfHappiness: computed("attitude", "health", () => { + }) + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ role: "sloth", abc: [], def: {}, ghi: alias("def") - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ levelOfHappiness: computed("attitude", "health", () => { }), @@ -95,8 +122,11 @@ eslintTester.run('order-in-components', rule, { }), actions: {} - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ abc: observer("aaaa", () => { }), @@ -108,8 +138,11 @@ eslintTester.run('order-in-components', rule, { customFunc() { return true; } - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ igh: service(), abc: [], @@ -131,8 +164,11 @@ eslintTester.run('order-in-components', rule, { customFunc() { return true; } - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ init() { }, didReceiveAttrs() { @@ -159,8 +195,11 @@ eslintTester.run('order-in-components', rule, { }, actions: {} - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ test: service(), didReceiveAttrs() { @@ -168,8 +207,11 @@ eslintTester.run('order-in-components', rule, { tSomeAction: task(function* (url) { }) - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ test: service(), test2: computed.equal("asd", "qwe"), @@ -179,8 +221,11 @@ eslintTester.run('order-in-components', rule, { tSomeAction: task(function* (url) { }).restartable() - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ test: service(), someEmptyMethod() {}, @@ -194,8 +239,11 @@ eslintTester.run('order-in-components', rule, { _anotherPrivateFnc() { return true; } - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ classNameBindings: ["filterDateSelectClass"], content: [], currentMonthEndDate: null, @@ -204,41 +252,54 @@ eslintTester.run('order-in-components', rule, { optionLabelPath: "label", typeOfDate: null, action: K - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ role: "sloth", levelOfHappiness: computed.or("asd", "qwe"), actions: {} - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ role: "sloth", levelOfHappiness: computed(function() {}), actions: {} - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ role: "sloth", levelOfHappiness: computed(function() { }), actions: {} - });`, + }); + `, { - code: `export default Component.extend({ - role: "sloth", + code: ` + import Component from '@ember/component'; + export default Component.extend({ + role: "sloth", - computed1: computed(function() { - }), - computed2: alias('computed1'), + computed1: computed(function() { + }), + computed2: alias('computed1'), - actions: {}, + actions: {}, - foobar: Ember.inject.service(), - });`, + foobar: Ember.inject.service(), + }); + `, options: [ { order: ['property', 'multi-line-function', 'single-line-function', 'actions'], @@ -246,64 +307,85 @@ eslintTester.run('order-in-components', rule, { ], }, { - code: `export default Component.extend({ - role: "sloth", + code: ` + import Component from '@ember/component'; + export default Component.extend({ + role: "sloth", - computed1: alias('computed2'), - computed2: computed(function() { - }), - computed3: alias('computed1'), + computed1: alias('computed2'), + computed2: computed(function() { + }), + computed3: alias('computed1'), - actions: {}, + actions: {}, - foobar: Ember.inject.service(), - });`, + foobar: Ember.inject.service(), + }); + `, options: [ { order: ['property', ['single-line-function', 'multi-line-function'], 'actions'], }, ], }, - `export default Component.extend({ + ` + import Component from '@ember/component'; + export default Component.extend({ role: "sloth", qwe: foo ? 'bar' : null, abc: [], def: {}, ghi: alias("def") - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ template: hbs\`Hello world {{name}}\`, name: "Jon Snow", actions: {} - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ layout, tabindex: -1, someComputedValue: computed.reads('count'), - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ foo: computed(function() { }).volatile(), bar: computed(function() { }) - });`, - `export default Component.extend({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend({ onFoo() {}, onFoo: () => {}, foo: computed(function() { }).volatile(), bar() { const foo = 'bar'} - });`, + }); + `, { - code: `export default Component.extend({ - onFoo() {}, - onFoo: () => {}, - foo: computed(function() { - }).volatile(), - bar() { const foo = 'bar'} - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + onFoo() {}, + onFoo: () => {}, + foo: computed(function() { + }).volatile(), + bar() { const foo = 'bar'} + }); + `, options: [ { order: [ @@ -319,150 +401,172 @@ eslintTester.run('order-in-components', rule, { ], invalid: [ { - code: `export default Component.extend({ - actions: {}, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + actions: {}, - role: "sloth", + role: "sloth", - vehicle: alias("car"), + vehicle: alias("car"), - levelOfHappiness: computed("attitude", "health", () => { - }) - });`, + levelOfHappiness: computed("attitude", "health", () => { + }) + }); + `, errors: [ { - message: 'The "role" property should be above the actions hash on line 2', - line: 4, + message: 'The "role" property should be above the actions hash on line 4', + line: 6, }, { - message: 'The "vehicle" single-line function should be above the actions hash on line 2', - line: 6, + message: 'The "vehicle" single-line function should be above the actions hash on line 4', + line: 8, }, { message: - 'The "levelOfHappiness" multi-line function should be above the actions hash on line 2', - line: 8, + 'The "levelOfHappiness" multi-line function should be above the actions hash on line 4', + line: 10, }, ], }, { - code: `export default Component.extend({ - vehicle: alias("car"), + code: ` + import Component from '@ember/component'; + export default Component.extend({ + vehicle: alias("car"), - role: "sloth", + role: "sloth", - levelOfHappiness: computed("attitude", "health", () => { - }), + levelOfHappiness: computed("attitude", "health", () => { + }), - actions: {} - });`, + actions: {} + }); + `, errors: [ { message: - 'The "role" property should be above the "vehicle" single-line function on line 2', - line: 4, + 'The "role" property should be above the "vehicle" single-line function on line 4', + line: 6, }, ], }, { - code: `export default Component.extend({ - levelOfHappiness: computed("attitude", "health", () => { - }), + code: ` + import Component from '@ember/component'; + export default Component.extend({ + levelOfHappiness: computed("attitude", "health", () => { + }), - vehicle: alias("car"), + vehicle: alias("car"), - role: "sloth", + role: "sloth", - actions: {} - });`, + actions: {} + }); + `, errors: [ { message: - 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 2', - line: 5, + 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 4', + line: 7, }, { message: - 'The "role" property should be above the "levelOfHappiness" multi-line function on line 2', - line: 7, + 'The "role" property should be above the "levelOfHappiness" multi-line function on line 4', + line: 9, }, ], }, { - code: `export default Component.extend(TestMixin, { - levelOfHappiness: computed("attitude", "health", () => { - }), + code: ` + import Component from '@ember/component'; + export default Component.extend(TestMixin, { + levelOfHappiness: computed("attitude", "health", () => { + }), - vehicle: alias("car"), + vehicle: alias("car"), - role: "sloth", + role: "sloth", - actions: {} - });`, + actions: {} + }); + `, errors: [ { message: - 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 2', - line: 5, + 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 4', + line: 7, }, { message: - 'The "role" property should be above the "levelOfHappiness" multi-line function on line 2', - line: 7, + 'The "role" property should be above the "levelOfHappiness" multi-line function on line 4', + line: 9, }, ], }, { - code: `export default Component.extend(TestMixin, TestMixin2, { - levelOfHappiness: computed("attitude", "health", () => { - }), + code: ` + import Component from '@ember/component'; + export default Component.extend(TestMixin, TestMixin2, { + levelOfHappiness: computed("attitude", "health", () => { + }), - vehicle: alias("car"), + vehicle: alias("car"), - role: "sloth", + role: "sloth", - actions: {} - });`, + actions: {} + }); + `, errors: [ { message: - 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 2', - line: 5, + 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 4', + line: 7, }, { message: - 'The "role" property should be above the "levelOfHappiness" multi-line function on line 2', - line: 7, + 'The "role" property should be above the "levelOfHappiness" multi-line function on line 4', + line: 9, }, ], }, { - code: `export default Component.extend({ - abc: true, - i18n: service() - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + abc: true, + i18n: service() + }); + `, errors: [ { - message: 'The "i18n" service injection should be above the "abc" property on line 2', - line: 3, + message: 'The "i18n" service injection should be above the "abc" property on line 4', + line: 5, }, ], }, { - code: `export default Component.extend({ - vehicle: alias("car"), - i18n: service() - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + vehicle: alias("car"), + i18n: service() + }); + `, errors: [ { message: - 'The "i18n" service injection should be above the "vehicle" single-line function on line 2', - line: 3, + 'The "i18n" service injection should be above the "vehicle" single-line function on line 4', + line: 5, }, ], }, { code: ` + import Component from '@ember/component'; import { inject } from '@ember/service'; export default Component.extend({ vehicle: alias("car"), @@ -472,287 +576,341 @@ eslintTester.run('order-in-components', rule, { errors: [ { message: - 'The "i18n" service injection should be above the "vehicle" single-line function on line 4', - line: 5, + 'The "i18n" service injection should be above the "vehicle" single-line function on line 5', + line: 6, }, ], }, { - code: `export default Component.extend({ - levelOfHappiness: observer("attitude", "health", () => { - }), - vehicle: alias("car") - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + levelOfHappiness: observer("attitude", "health", () => { + }), + vehicle: alias("car") + }); + `, errors: [ { message: - 'The "vehicle" single-line function should be above the "levelOfHappiness" observer on line 2', - line: 4, + 'The "vehicle" single-line function should be above the "levelOfHappiness" observer on line 4', + line: 6, }, ], }, { - code: `export default Component.extend({ - levelOfHappiness: observer("attitude", "health", () => { - }), - aaa: computed("attitude", "health", () => { - }) - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + levelOfHappiness: observer("attitude", "health", () => { + }), + aaa: computed("attitude", "health", () => { + }) + }); + `, errors: [ { message: - 'The "aaa" multi-line function should be above the "levelOfHappiness" observer on line 2', - line: 4, + 'The "aaa" multi-line function should be above the "levelOfHappiness" observer on line 4', + line: 6, }, ], }, { - code: `export default Component.extend({ - init() { - }, - levelOfHappiness: observer("attitude", "health", () => { - }) - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + init() { + }, + levelOfHappiness: observer("attitude", "health", () => { + }) + }); + `, errors: [ { message: - 'The "levelOfHappiness" observer should be above the "init" lifecycle hook on line 2', - line: 4, + 'The "levelOfHappiness" observer should be above the "init" lifecycle hook on line 4', + line: 6, }, ], }, { - code: `export default Component.extend({ - actions: {}, - init() { - } - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + actions: {}, + init() { + } + }); + `, errors: [ { - message: 'The "init" lifecycle hook should be above the actions hash on line 2', - line: 3, + message: 'The "init" lifecycle hook should be above the actions hash on line 4', + line: 5, }, ], }, { - code: `export default Component.extend({ - customFunc() { - const foo = 'bar'; - }, - actions: {} - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + customFunc() { + const foo = 'bar'; + }, + actions: {} + }); + `, errors: [ { - message: 'The actions hash should be above the "customFunc" method on line 2', - line: 5, + message: 'The actions hash should be above the "customFunc" method on line 4', + line: 7, }, ], }, { - code: `export default Component.extend({ - tAction: test(function() { - }), - actions: {} - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + tAction: test(function() { + }), + actions: {} + }); + `, errors: [ { - message: 'The actions hash should be above the "tAction" method on line 2', - line: 4, + message: 'The actions hash should be above the "tAction" method on line 4', + line: 6, }, ], }, { - code: `export default Component.extend(TestMixin, TestMixin2, { - foo: alias("car"), + code: ` + import Component from '@ember/component'; + export default Component.extend(TestMixin, TestMixin2, { + foo: alias("car"), - levelOfHappiness: computed("attitude", "health", () => { - }), + levelOfHappiness: computed("attitude", "health", () => { + }), - vehicle: alias("car"), + vehicle: alias("car"), - role: "sloth", + role: "sloth", - actions: {} - });`, + actions: {} + }); + `, errors: [ { message: - 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 4', - line: 7, + 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 6', + line: 9, }, { - message: 'The "role" property should be above the "foo" single-line function on line 2', - line: 9, + message: 'The "role" property should be above the "foo" single-line function on line 4', + line: 11, }, ], }, { - code: `let foo = 'foo'; + code: ` + import Component from '@ember/component'; + let foo = 'foo'; - export default Component.extend(TestMixin, TestMixin2, { - actions: {}, - [foo]: 'foo', - });`, + export default Component.extend(TestMixin, TestMixin2, { + actions: {}, + [foo]: 'foo', + }); + `, errors: [ { - message: 'The property should be above the actions hash on line 4', - line: 5, + message: 'The property should be above the actions hash on line 6', + line: 7, }, ], }, { filename: 'example-app/components/some-component/component.js', - code: `export default CustomComponent.extend({ - actions: {}, - role: "sloth", - });`, + code: ` + import CustomComponent from '@ember/component'; + export default CustomComponent.extend({ + actions: {}, + role: "sloth", + }); + `, errors: [ { - message: 'The "role" property should be above the actions hash on line 2', - line: 3, + message: 'The "role" property should be above the actions hash on line 4', + line: 5, }, ], }, { filename: 'example-app/components/some-component.js', - code: `export default CustomComponent.extend({ - actions: {}, - role: "sloth", - });`, + code: ` + import CustomComponent from '@ember/component'; + export default CustomComponent.extend({ + actions: {}, + role: "sloth", + }); + `, errors: [ { - message: 'The "role" property should be above the actions hash on line 2', - line: 3, + message: 'The "role" property should be above the actions hash on line 4', + line: 5, }, ], }, { filename: 'example-app/twisted-path/some-component.js', - code: `export default Component.extend({ - actions: {}, - role: "sloth", - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + actions: {}, + role: "sloth", + }); + `, errors: [ { - message: 'The "role" property should be above the actions hash on line 2', - line: 3, + message: 'The "role" property should be above the actions hash on line 4', + line: 5, }, ], }, { - code: `export default Component.extend({ - name: "Jon Snow", - actions: {}, - template: hbs\`Hello world {{name}}\`, - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + name: "Jon Snow", + actions: {}, + template: hbs\`Hello world {{name}}\`, + }); + `, errors: [ { - message: 'The "template" property should be above the actions hash on line 3', - line: 4, + message: 'The "template" property should be above the actions hash on line 5', + line: 6, }, ], }, { - code: `export default Component.extend({ - layout, - someComputedValue: computed.reads('count'), + code: ` + import Component from '@ember/component'; + export default Component.extend({ + layout, + someComputedValue: computed.reads('count'), - tabindex: -1, - });`, + tabindex: -1, + }); + `, errors: [ { message: - 'The "tabindex" property should be above the "someComputedValue" single-line function on line 3', - line: 5, + 'The "tabindex" property should be above the "someComputedValue" single-line function on line 5', + line: 7, }, ], }, { - code: `export default Component.extend({ - foo: computed(function() { - }).volatile(), - name: "Jon Snow", - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + foo: computed(function() { + }).volatile(), + name: "Jon Snow", + }); + `, errors: [ { - message: 'The "name" property should be above the "foo" multi-line function on line 2', - line: 4, + message: 'The "name" property should be above the "foo" multi-line function on line 4', + line: 6, }, ], }, { - code: `export default Component.extend({ - actions: {}, - didReceiveAttrs() {}, - willDestroyElement() {}, - didInsertElement() {}, - init() {}, - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + actions: {}, + didReceiveAttrs() {}, + willDestroyElement() {}, + didInsertElement() {}, + init() {}, + }); + `, errors: [ { message: - 'The "didReceiveAttrs" lifecycle hook should be above the actions hash on line 2', - line: 3, + 'The "didReceiveAttrs" lifecycle hook should be above the actions hash on line 4', + line: 5, }, { message: - 'The "willDestroyElement" lifecycle hook should be above the actions hash on line 2', - line: 4, + 'The "willDestroyElement" lifecycle hook should be above the actions hash on line 4', + line: 6, }, { message: - 'The "didInsertElement" lifecycle hook should be above the actions hash on line 2', - line: 5, + 'The "didInsertElement" lifecycle hook should be above the actions hash on line 4', + line: 7, }, { - message: 'The "init" lifecycle hook should be above the actions hash on line 2', - line: 6, + message: 'The "init" lifecycle hook should be above the actions hash on line 4', + line: 8, }, ], }, { - code: `export default Component.extend({ - foo: computed(function() { - }).volatile(), - onFoo() {}, - bar() { const foo = 'bar'}, - onBar: () => {} - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + foo: computed(function() { + }).volatile(), + onFoo() {}, + bar() { const foo = 'bar'}, + onBar: () => {} + }); + `, errors: [ { message: - 'The "onFoo" empty method should be above the "foo" multi-line function on line 2', - line: 4, + 'The "onFoo" empty method should be above the "foo" multi-line function on line 4', + line: 6, }, { message: - 'The "onBar" empty method should be above the "foo" multi-line function on line 2', - line: 6, + 'The "onBar" empty method should be above the "foo" multi-line function on line 4', + line: 8, }, ], }, { - code: `export default Component.extend({ - levelOfHappiness: computed("attitude", "health", () => { - }), + code: ` + import Component from '@ember/component'; + export default Component.extend({ + levelOfHappiness: computed("attitude", "health", () => { + }), - vehicle: alias("car"), + vehicle: alias("car"), - actions: {} - });`, - output: `export default Component.extend({ - vehicle: alias("car"), + actions: {} + }); + `, + output: ` + import Component from '@ember/component'; + export default Component.extend({ + vehicle: alias("car"), - levelOfHappiness: computed("attitude", "health", () => { - }), + levelOfHappiness: computed("attitude", "health", () => { + }), - actions: {} - });`, + actions: {} + }); + `, errors: [ { message: - 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 2', - line: 5, + 'The "vehicle" single-line function should be above the "levelOfHappiness" multi-line function on line 4', + line: 7, }, ], }, diff --git a/tests/lib/rules/order-in-controllers.js b/tests/lib/rules/order-in-controllers.js index 1deac90600..73fe96ad42 100644 --- a/tests/lib/rules/order-in-controllers.js +++ b/tests/lib/rules/order-in-controllers.js @@ -17,8 +17,13 @@ const eslintTester = new RuleTester({ eslintTester.run('order-in-controllers', rule, { valid: [ - 'export default Controller.extend();', - `export default Controller.extend({ + ` + import Controller from '@ember/controller'; + export default Controller.extend(); + `, + ` + import Controller from '@ember/controller'; + export default Controller.extend({ application: controller(), currentUser: service(), queryParams: [], @@ -27,8 +32,11 @@ eslintTester.run('order-in-controllers', rule, { _customAction() { const foo = 'bar'; }, _customAction2: function() { const foo = 'bar'; }, tSomeTask: task(function* () {}) - });`, - `export default Controller.extend({ + }); + `, + ` + import Controller from '@ember/controller'; + export default Controller.extend({ currentUser: inject(), queryParams: [], customProp: "test", @@ -36,31 +44,41 @@ eslintTester.run('order-in-controllers', rule, { _customAction() {}, _customAction2: function() {}, tSomeTask: task(function* () {}) - });`, - `export default Controller.extend({ + }); + `, + ` + import Controller from '@ember/controller'; + export default Controller.extend({ queryParams: [], customProp: "test", comp: computed("test", function() {}), obs: observer("asd", function() {}), actions: {} - });`, - `export default Controller.extend({ + }); + `, + ` + import Controller from '@ember/controller'; + export default Controller.extend({ customProp: "test", comp: computed("test", function() {}), comp2: computed("test", function() { }), actions: {}, _customAction() { const foo = 'bar'; } - });`, + }); + `, { - code: `export default Controller.extend({ - actions: {}, - comp: computed("test", function() {}), - customProp: "test", - comp2: computed("test", function() { - }), - _customAction() { const foo = 'bar'; } - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + actions: {}, + comp: computed("test", function() {}), + customProp: "test", + comp2: computed("test", function() { + }), + _customAction() { const foo = 'bar'; } + }); + `, options: [ { order: ['actions', 'single-line-function'], @@ -68,10 +86,13 @@ eslintTester.run('order-in-controllers', rule, { ], }, { - code: `export default Controller.extend({ - queryParams: [], - currentUser: service(), - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + queryParams: [], + currentUser: service(), + }); + `, options: [ { order: ['query-params', 'service'], @@ -79,10 +100,13 @@ eslintTester.run('order-in-controllers', rule, { ], }, { - code: `export default Controller.extend({ - queryParams: [], - application: controller(), - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + queryParams: [], + application: controller(), + }); + `, options: [ { order: ['query-params', 'controller'], @@ -90,185 +114,222 @@ eslintTester.run('order-in-controllers', rule, { ], }, ` - export default Controller.extend({ - foo: service(), - someProp: null, - init() { - this._super(...arguments); - }, - actions: { - onKeyPress: function (event) {} - } - }); - `, + import Controller from '@ember/controller'; + export default Controller.extend({ + foo: service(), + someProp: null, + init() { + this._super(...arguments); + }, + actions: { + onKeyPress: function (event) {} + } + }); + `, ` - export default Controller.extend({ - foo: service(), - init() { - this._super(...arguments); - }, - customFoo() {} - }); - `, + import Controller from '@ember/controller'; + export default Controller.extend({ + foo: service(), + init() { + this._super(...arguments); + }, + customFoo() {} + }); + `, ` - export default Controller.extend({ - foo: service(), - init() { - this._super(...arguments); - } - }); - `, + import Controller from '@ember/controller'; + export default Controller.extend({ + foo: service(), + init() { + this._super(...arguments); + } + }); + `, ], invalid: [ { - code: `export default Controller.extend({ - queryParams: [], - currentUser: service() - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + queryParams: [], + currentUser: service() + }); + `, errors: [ { message: - 'The "currentUser" service injection should be above the "queryParams" property on line 2', - line: 3, + 'The "currentUser" service injection should be above the "queryParams" property on line 4', + line: 5, }, ], }, { - code: `export default Controller.extend({ - queryParams: [], - currentUser: inject() - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + queryParams: [], + currentUser: inject() + }); + `, errors: [ { message: - 'The "currentUser" service injection should be above the "queryParams" property on line 2', - line: 3, + 'The "currentUser" service injection should be above the "queryParams" property on line 4', + line: 5, }, ], }, { - code: `export default Controller.extend({ - currentUser: service(), - customProp: "test", - queryParams: [] - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + currentUser: service(), + customProp: "test", + queryParams: [] + }); + `, errors: [ { - message: 'The "queryParams" property should be above the "customProp" property on line 3', - line: 4, + message: 'The "queryParams" property should be above the "customProp" property on line 5', + line: 6, }, ], }, { - code: `export default Controller.extend({ - queryParams: [], - actions: {}, - customProp: "test" - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + queryParams: [], + actions: {}, + customProp: "test" + }); + `, errors: [ { - message: 'The "customProp" property should be above the actions hash on line 3', - line: 4, + message: 'The "customProp" property should be above the actions hash on line 5', + line: 6, }, ], }, { - code: `export default Controller.extend({ - queryParams: [], - _customAction() { const foo = 'bar'; }, - actions: {} - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + queryParams: [], + _customAction() { const foo = 'bar'; }, + actions: {} + }); + `, errors: [ { - message: 'The actions hash should be above the "_customAction" method on line 3', - line: 4, + message: 'The actions hash should be above the "_customAction" method on line 5', + line: 6, }, ], }, { - code: `export default Controller.extend({ - test: "asd", - queryParams: [], - actions: {} - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + test: "asd", + queryParams: [], + actions: {} + }); + `, errors: [ { - message: 'The "queryParams" property should be above the "test" property on line 2', - line: 3, + message: 'The "queryParams" property should be above the "test" property on line 4', + line: 5, }, ], }, { - code: `export default Controller.extend({ - currentUser: service(), - application: controller() - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + currentUser: service(), + application: controller() + }); + `, errors: [ { message: - 'The "application" controller injection should be above the "currentUser" service injection on line 2', - line: 3, + 'The "application" controller injection should be above the "currentUser" service injection on line 4', + line: 5, }, ], }, { - code: `export default Controller.extend({ - test: "asd", - obs: observer("asd", function() {}), - comp: computed("asd", function() {}), - actions: {} - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + test: "asd", + obs: observer("asd", function() {}), + comp: computed("asd", function() {}), + actions: {} + }); + `, errors: [ { - message: 'The "comp" single-line function should be above the "obs" observer on line 3', - line: 4, + message: 'The "comp" single-line function should be above the "obs" observer on line 5', + line: 6, }, ], }, { filename: 'example-app/controllers/some-controller.js', - code: `export default CustomController.extend({ - queryParams: [], - currentUser: service() - });`, + code: ` + import CustomController from '@ember/controller'; + export default CustomController.extend({ + queryParams: [], + currentUser: service() + }); + `, errors: [ { message: - 'The "currentUser" service injection should be above the "queryParams" property on line 2', - line: 3, + 'The "currentUser" service injection should be above the "queryParams" property on line 4', + line: 5, }, ], }, { filename: 'example-app/some-feature/controller.js', - code: `export default CustomController.extend({ - queryParams: [], - currentUser: service() - });`, + code: ` + import CustomController from '@ember/controller'; + export default CustomController.extend({ + queryParams: [], + currentUser: service() + }); + `, errors: [ { message: - 'The "currentUser" service injection should be above the "queryParams" property on line 2', - line: 3, + 'The "currentUser" service injection should be above the "queryParams" property on line 4', + line: 5, }, ], }, { filename: 'example-app/twised-path/some-controller.js', - code: `export default Controller.extend({ - queryParams: [], - currentUser: service() - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + queryParams: [], + currentUser: service() + }); + `, errors: [ { message: - 'The "currentUser" service injection should be above the "queryParams" property on line 2', - line: 3, + 'The "currentUser" service injection should be above the "queryParams" property on line 4', + line: 5, }, ], }, { code: ` + import Controller from '@ember/controller'; export default Controller.extend({ foo: service(), actions: { @@ -281,13 +342,14 @@ eslintTester.run('order-in-controllers', rule, { `, errors: [ { - message: 'The "init" lifecycle hook should be above the actions hash on line 4', - line: 7, + message: 'The "init" lifecycle hook should be above the actions hash on line 5', + line: 8, }, ], }, { code: ` + import Controller from '@ember/controller'; export default Controller.extend({ foo: service(), customFoo() {}, @@ -299,13 +361,14 @@ eslintTester.run('order-in-controllers', rule, { errors: [ { message: - 'The "init" lifecycle hook should be above the "customFoo" empty method on line 4', - line: 5, + 'The "init" lifecycle hook should be above the "customFoo" empty method on line 5', + line: 6, }, ], }, { code: ` + import Controller from '@ember/controller'; export default Controller.extend({ init() { this._super(...arguments); @@ -316,13 +379,14 @@ eslintTester.run('order-in-controllers', rule, { errors: [ { message: - 'The "foo" service injection should be above the "init" lifecycle hook on line 3', - line: 6, + 'The "foo" service injection should be above the "init" lifecycle hook on line 4', + line: 7, }, ], }, { code: ` + import Controller from '@ember/controller'; export default Controller.extend({ init() { this._super(...arguments); @@ -332,45 +396,53 @@ eslintTester.run('order-in-controllers', rule, { `, errors: [ { - message: 'The "someProp" property should be above the "init" lifecycle hook on line 3', - line: 6, + message: 'The "someProp" property should be above the "init" lifecycle hook on line 4', + line: 7, }, ], }, { code: // whitespace is preserved inside `` and it's breaking the test - `export default Controller.extend({ + `import Controller from '@ember/controller'; +export default Controller.extend({ queryParams: [], currentUser: service(), });`, - output: `export default Controller.extend({ + output: `import Controller from '@ember/controller'; +export default Controller.extend({ currentUser: service(), queryParams: [], });`, errors: [ { message: - 'The "currentUser" service injection should be above the "queryParams" property on line 2', - line: 3, + 'The "currentUser" service injection should be above the "queryParams" property on line 3', + line: 4, }, ], }, { - code: `export default Controller.extend({ - test: "asd", - queryParams: [], - actions: {} - });`, - output: `export default Controller.extend({ - queryParams: [], - test: "asd", - actions: {} - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + test: "asd", + queryParams: [], + actions: {} + }); + `, + output: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + queryParams: [], + test: "asd", + actions: {} + }); + `, errors: [ { - message: 'The "queryParams" property should be above the "test" property on line 2', - line: 3, + message: 'The "queryParams" property should be above the "test" property on line 4', + line: 5, }, ], }, diff --git a/tests/lib/rules/order-in-routes.js b/tests/lib/rules/order-in-routes.js index bcd7cede94..387a250e0a 100644 --- a/tests/lib/rules/order-in-routes.js +++ b/tests/lib/rules/order-in-routes.js @@ -17,8 +17,13 @@ const eslintTester = new RuleTester({ eslintTester.run('order-in-routes', rule, { valid: [ - 'export default Route.extend();', - `export default Route.extend({ + ` + import Route from '@ember/routing/route'; + export default Route.extend(); + `, + ` + import Route from '@ember/routing/route'; + export default Route.extend({ currentUser: service(), queryParams: {}, customProp: "test", @@ -40,7 +45,9 @@ eslintTester.run('order-in-routes', rule, { _customAction2: function() { const foo = 'bar'; }, tSomeTask: task(function* () {}) });`, - `export default Route.extend({ + ` + import Route from '@ember/routing/route'; + export default Route.extend({ currentUser: inject(), queryParams: {}, customProp: "test", @@ -55,7 +62,9 @@ eslintTester.run('order-in-routes', rule, { _customAction2: function() {}, tSomeTask: task(function* () {}) });`, - `export default Route.extend({ + ` + import Route from '@ember/routing/route'; + export default Route.extend({ levelOfHappiness: computed("attitude", "health", () => { }), model() {}, @@ -64,12 +73,16 @@ eslintTester.run('order-in-routes', rule, { }, _customAction() { const foo = 'bar'; } });`, - `export default Route.extend({ + ` + import Route from '@ember/routing/route'; + export default Route.extend({ init() {}, model() {}, render() {}, });`, - `export default Route.extend({ + ` + import Route from '@ember/routing/route'; + export default Route.extend({ mergedProperties: {}, vehicle: alias("car"), levelOfHappiness: computed("attitude", "health", () => { @@ -77,18 +90,23 @@ eslintTester.run('order-in-routes', rule, { model() {}, actions: {} });`, - `export default Route.extend({ + ` + import Route from '@ember/routing/route'; + export default Route.extend({ mergedProperties: {}, test: "asd", vehicle: alias("car"), model() {} });`, { - code: `export default Route.extend({ - model() {}, - beforeModel() {}, - currentUser: service(), - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + model() {}, + beforeModel() {}, + currentUser: service(), + }); + `, options: [ { order: ['model', 'lifecycle-hook', 'service'], @@ -96,12 +114,15 @@ eslintTester.run('order-in-routes', rule, { ], }, { - code: `export default Route.extend({ - deactivate() {}, - beforeModel() {}, - currentUser: service(), - model() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + deactivate() {}, + beforeModel() {}, + currentUser: service(), + model() {} + }); + `, options: [ { order: ['lifecycle-hook', 'service', 'model'], @@ -109,13 +130,16 @@ eslintTester.run('order-in-routes', rule, { ], }, { - code: `export default Route.extend({ - deactivate() {}, - setupController() {}, - beforeModel() {}, - currentUser: service(), - model() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + deactivate() {}, + setupController() {}, + beforeModel() {}, + currentUser: service(), + model() {} + }); + `, options: [ { order: [['deactivate', 'setupController', 'beforeModel'], 'service', 'model'], @@ -123,271 +147,310 @@ eslintTester.run('order-in-routes', rule, { ], }, ` - export default Route.extend({ - foo: service(), - init() { - this._super(...arguments); - }, - actions: {} - }); - `, + import Route from '@ember/routing/route'; + export default Route.extend({ + foo: service(), + init() { + this._super(...arguments); + }, + actions: {} + }); + `, ` - export default Route.extend({ - foo: service(), - init() { - this._super(...arguments); - }, - customFoo() {} - }); - `, + import Route from '@ember/routing/route'; + export default Route.extend({ + foo: service(), + init() { + this._super(...arguments); + }, + customFoo() {} + }); + `, ], invalid: [ { - code: `export default Route.extend({ - queryParams: {}, - currentUser: service(), - customProp: "test", - beforeModel() {}, - model() {}, - vehicle: alias("car"), - actions: {}, - _customAction() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + queryParams: {}, + currentUser: service(), + customProp: "test", + beforeModel() {}, + model() {}, + vehicle: alias("car"), + actions: {}, + _customAction() {} + }); + `, errors: [ { message: - 'The "currentUser" service injection should be above the inherited "queryParams" property on line 2', - line: 3, + 'The "currentUser" service injection should be above the inherited "queryParams" property on line 4', + line: 5, }, { message: - 'The "vehicle" single-line function should be above the "beforeModel" lifecycle hook on line 5', - line: 7, + 'The "vehicle" single-line function should be above the "beforeModel" lifecycle hook on line 7', + line: 9, }, ], }, { - code: `export default Route.extend({ - queryParams: {}, - currentUser: inject(), - customProp: "test", - beforeModel() {}, - model() {}, - vehicle: alias("car"), - actions: {}, - _customAction() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + queryParams: {}, + currentUser: inject(), + customProp: "test", + beforeModel() {}, + model() {}, + vehicle: alias("car"), + actions: {}, + _customAction() {} + }); + `, errors: [ { message: - 'The "currentUser" service injection should be above the inherited "queryParams" property on line 2', - line: 3, + 'The "currentUser" service injection should be above the inherited "queryParams" property on line 4', + line: 5, }, { message: - 'The "vehicle" single-line function should be above the "beforeModel" lifecycle hook on line 5', - line: 7, + 'The "vehicle" single-line function should be above the "beforeModel" lifecycle hook on line 7', + line: 9, }, ], }, { - code: `export default Route.extend({ - customProp: "test", - queryParams: {}, - beforeModel() {}, - model() {}, - actions: {}, - _customAction() {}, - levelOfHappiness: computed("attitude", "health", () => { - }) - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + customProp: "test", + queryParams: {}, + beforeModel() {}, + model() {}, + actions: {}, + _customAction() {}, + levelOfHappiness: computed("attitude", "health", () => { + }) + }); + `, errors: [ { message: - 'The inherited "queryParams" property should be above the "customProp" property on line 2', - line: 3, + 'The inherited "queryParams" property should be above the "customProp" property on line 4', + line: 5, }, { message: - 'The "levelOfHappiness" multi-line function should be above the "beforeModel" lifecycle hook on line 4', - line: 8, + 'The "levelOfHappiness" multi-line function should be above the "beforeModel" lifecycle hook on line 6', + line: 10, }, ], }, { - code: `export default Route.extend({ - customProp: "test", - queryParams: {}, - model() {}, - beforeModel() {}, - actions: {}, - _customAction() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + customProp: "test", + queryParams: {}, + model() {}, + beforeModel() {}, + actions: {}, + _customAction() {} + }); + `, errors: [ { message: - 'The inherited "queryParams" property should be above the "customProp" property on line 2', - line: 3, + 'The inherited "queryParams" property should be above the "customProp" property on line 4', + line: 5, }, { - message: 'The "beforeModel" lifecycle hook should be above the "model" hook on line 4', - line: 5, + message: 'The "beforeModel" lifecycle hook should be above the "model" hook on line 6', + line: 7, }, ], }, { - code: `export default Route.extend({ - queryParams: {}, - vehicle: alias("car"), - customProp: "test", - model() {}, - _customAction() { const foo = 'bar'; }, - actions: {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + queryParams: {}, + vehicle: alias("car"), + customProp: "test", + model() {}, + _customAction() { const foo = 'bar'; }, + actions: {} + }); + `, errors: [ { message: - 'The "customProp" property should be above the "vehicle" single-line function on line 3', - line: 4, + 'The "customProp" property should be above the "vehicle" single-line function on line 5', + line: 6, }, { - message: 'The actions hash should be above the "_customAction" method on line 6', - line: 7, + message: 'The actions hash should be above the "_customAction" method on line 8', + line: 9, }, ], }, { - code: `export default Route.extend({ - model() {}, - customProp: "test", - actions: {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + model() {}, + customProp: "test", + actions: {} + }); + `, errors: [ { - message: 'The "customProp" property should be above the "model" hook on line 2', - line: 3, + message: 'The "customProp" property should be above the "model" hook on line 4', + line: 5, }, ], }, { - code: `export default Route.extend({ - test: "asd", - mergedProperties: {}, - model() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + test: "asd", + mergedProperties: {}, + model() {} + }); + `, errors: [ { message: - 'The inherited "mergedProperties" property should be above the "test" property on line 2', - line: 3, + 'The inherited "mergedProperties" property should be above the "test" property on line 4', + line: 5, }, ], }, { - 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* () {}) - });`, + code: ` + import Route from '@ember/routing/route'; + 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* () {}) + }); + `, errors: [ { message: - 'The "redirect" lifecycle hook should be above the "setupController" lifecycle hook on line 11', - line: 12, + 'The "redirect" lifecycle hook should be above the "setupController" lifecycle hook on line 13', + line: 14, }, { message: - 'The "serialize" lifecycle hook should be above the "setupController" lifecycle hook on line 11', - line: 13, + 'The "serialize" lifecycle hook should be above the "setupController" lifecycle hook on line 13', + line: 15, }, { message: - 'The "activate" lifecycle hook should be above the "setupController" lifecycle hook on line 11', - line: 14, + 'The "activate" lifecycle hook should be above the "setupController" lifecycle hook on line 13', + line: 16, }, { message: - 'The "renderTemplate" lifecycle hook should be above the "deactivate" lifecycle hook on line 15', - line: 16, + 'The "renderTemplate" lifecycle hook should be above the "deactivate" lifecycle hook on line 17', + line: 18, }, { message: - 'The "resetController" lifecycle hook should be above the "deactivate" lifecycle hook on line 15', - line: 17, + 'The "resetController" lifecycle hook should be above the "deactivate" lifecycle hook on line 17', + line: 19, }, ], }, { - code: `export default Route.extend({ - test: "asd", - _test2() { const foo = 'bar'; }, - model() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + test: "asd", + _test2() { const foo = 'bar'; }, + model() {} + }); + `, errors: [ { - message: 'The "model" hook should be above the "_test2" method on line 3', - line: 4, + message: 'The "model" hook should be above the "_test2" method on line 5', + line: 6, }, ], }, { filename: 'example-app/routes/some-route.js', - code: `export default CustomRoute.extend({ - model() {}, - test: "asd", - });`, + code: ` + import CustomRoute from '@ember/routing/route'; + export default CustomRoute.extend({ + model() {}, + test: "asd", + }); + `, errors: [ { - message: 'The "test" property should be above the "model" hook on line 2', - line: 3, + message: 'The "test" property should be above the "model" hook on line 4', + line: 5, }, ], }, { filename: 'example-app/some-feature/route.js', - code: `export default CustomRoute.extend({ - model() {}, - test: "asd", - });`, + code: ` + import CustomRoute from '@ember/routing/route'; + export default CustomRoute.extend({ + model() {}, + test: "asd", + }); + `, errors: [ { - message: 'The "test" property should be above the "model" hook on line 2', - line: 3, + message: 'The "test" property should be above the "model" hook on line 4', + line: 5, }, ], }, { filename: 'example-app/twisted-path/some-file.js', - code: `export default Route.extend({ - model() {}, - test: "asd", - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + model() {}, + test: "asd", + }); + `, errors: [ { - message: 'The "test" property should be above the "model" hook on line 2', - line: 3, + message: 'The "test" property should be above the "model" hook on line 4', + line: 5, }, ], }, { code: ` + import Route from '@ember/routing/route'; export default Route.extend({ foo: service(), actions: {}, @@ -398,13 +461,14 @@ eslintTester.run('order-in-routes', rule, { `, errors: [ { - message: 'The "init" lifecycle hook should be above the actions hash on line 4', - line: 5, + message: 'The "init" lifecycle hook should be above the actions hash on line 5', + line: 6, }, ], }, { code: ` + import Route from '@ember/routing/route'; export default Route.extend({ foo: service(), customFoo() {}, @@ -416,13 +480,14 @@ eslintTester.run('order-in-routes', rule, { errors: [ { message: - 'The "init" lifecycle hook should be above the "customFoo" empty method on line 4', - line: 5, + 'The "init" lifecycle hook should be above the "customFoo" empty method on line 5', + line: 6, }, ], }, { code: ` + import Route from '@ember/routing/route'; export default Route.extend({ init() { this._super(...arguments); @@ -433,13 +498,14 @@ eslintTester.run('order-in-routes', rule, { errors: [ { message: - 'The "foo" service injection should be above the "init" lifecycle hook on line 3', - line: 6, + 'The "foo" service injection should be above the "init" lifecycle hook on line 4', + line: 7, }, ], }, { code: ` + import Route from '@ember/routing/route'; export default Route.extend({ init() { this._super(...arguments); @@ -449,114 +515,133 @@ eslintTester.run('order-in-routes', rule, { `, errors: [ { - message: 'The "someProp" property should be above the "init" lifecycle hook on line 3', - line: 6, + message: 'The "someProp" property should be above the "init" lifecycle hook on line 4', + line: 7, }, ], }, { - code: `export default Route.extend({ - queryParams: {}, - currentUser: service(), - customProp: "test", - beforeModel() {}, - model() {}, - vehicle: alias("car"), - actions: {}, - _customAction() {} - });`, - output: `export default Route.extend({ - currentUser: service(), - queryParams: {}, - customProp: "test", - vehicle: alias("car"), - beforeModel() {}, - model() {}, - actions: {}, - _customAction() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + queryParams: {}, + currentUser: service(), + customProp: "test", + beforeModel() {}, + model() {}, + vehicle: alias("car"), + actions: {}, + _customAction() {} + }); + `, + output: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + currentUser: service(), + queryParams: {}, + customProp: "test", + vehicle: alias("car"), + beforeModel() {}, + model() {}, + actions: {}, + _customAction() {} + }); + `, errors: [ { message: - 'The "currentUser" service injection should be above the inherited "queryParams" property on line 2', - line: 3, + 'The "currentUser" service injection should be above the inherited "queryParams" property on line 4', + line: 5, }, { message: - 'The "vehicle" single-line function should be above the "beforeModel" lifecycle hook on line 5', - line: 7, + 'The "vehicle" single-line function should be above the "beforeModel" lifecycle hook on line 7', + line: 9, }, ], }, { - code: `export default Route.extend({ - customProp: "test", - // queryParams line comment - queryParams: {}, - model() {}, - /** - * actions block comment - */ - actions: {}, - _customAction() {} - });`, - output: `export default Route.extend({ - // queryParams line comment - queryParams: {}, - customProp: "test", - model() {}, - /** - * actions block comment - */ - actions: {}, - _customAction() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + customProp: "test", + // queryParams line comment + queryParams: {}, + model() {}, + /** + * actions block comment + */ + actions: {}, + _customAction() {} + }); + `, + output: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + // queryParams line comment + queryParams: {}, + customProp: "test", + model() {}, + /** + * actions block comment + */ + actions: {}, + _customAction() {} + }); + `, errors: [ { message: - 'The inherited "queryParams" property should be above the "customProp" property on line 2', - line: 4, + 'The inherited "queryParams" property should be above the "customProp" property on line 4', + line: 6, }, ], }, { - code: `export default Route.extend({ - customProp: "test", - model() {}, - /** - * beforeModel block comment - */ - beforeModel() {}, - /** - * actions block comment - */ - actions: {}, - _customAction() {} - });`, - output: `export default Route.extend({ - customProp: "test", - /** - * beforeModel block comment - */ - beforeModel() {}, - model() {}, - /** - * actions block comment - */ - actions: {}, - _customAction() {} - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + customProp: "test", + model() {}, + /** + * beforeModel block comment + */ + beforeModel() {}, + /** + * actions block comment + */ + actions: {}, + _customAction() {} + }); + `, + output: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + customProp: "test", + /** + * beforeModel block comment + */ + beforeModel() {}, + model() {}, + /** + * actions block comment + */ + actions: {}, + _customAction() {} + }); + `, errors: [ { - message: 'The "beforeModel" lifecycle hook should be above the "model" hook on line 3', - line: 7, + message: 'The "beforeModel" lifecycle hook should be above the "model" hook on line 5', + line: 9, }, ], }, { code: // whitespace is preserved inside `` and it's breaking the test - `export default Route.extend({ + `import Route from '@ember/routing/route'; +export default Route.extend({ customProp: "test", /** * actions block comment @@ -567,7 +652,8 @@ eslintTester.run('order-in-routes', rule, { */ beforeModel() {} });`, - output: `export default Route.extend({ + output: `import Route from '@ember/routing/route'; +export default Route.extend({ customProp: "test", /** * beforeModel block comment @@ -580,52 +666,60 @@ eslintTester.run('order-in-routes', rule, { });`, errors: [ { - message: 'The "beforeModel" lifecycle hook should be above the actions hash on line 6', - line: 10, + message: 'The "beforeModel" lifecycle hook should be above the actions hash on line 7', + line: 11, }, ], }, { code: // whitespace is preserved inside `` and it's breaking the test - `export default Route.extend({ + `import Route from '@ember/routing/route'; +export default Route.extend({ model() {}, test: "asd" });`, - output: `export default Route.extend({ + output: `import Route from '@ember/routing/route'; +export default Route.extend({ test: "asd", model() {}, });`, errors: [ { - message: 'The "test" property should be above the "model" hook on line 2', - line: 3, + message: 'The "test" property should be above the "model" hook on line 3', + line: 4, }, ], }, { - code: `export default Route.extend({ + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ - model() {}, + model() {}, - test: "asd", + test: "asd", - actions: {} + actions: {} - });`, - output: `export default Route.extend({ + }); + `, + output: ` + import Route from '@ember/routing/route'; + export default Route.extend({ - test: "asd", + test: "asd", - model() {}, + model() {}, - actions: {} + actions: {} - });`, + }); + `, errors: [ { - message: 'The "test" property should be above the "model" hook on line 3', - line: 5, + message: 'The "test" property should be above the "model" hook on line 5', + line: 7, }, ], }, diff --git a/tests/lib/rules/require-super-in-init.js b/tests/lib/rules/require-super-in-init.js index ff61ce00c4..e4b7e1c7d7 100644 --- a/tests/lib/rules/require-super-in-init.js +++ b/tests/lib/rules/require-super-in-init.js @@ -17,425 +17,448 @@ const message = 'Call this._super(...arguments) in init hook'; eslintTester.run('require-super-in-init', rule, { valid: [ - `export default Component.extend({ + ` + import Component from '@ember/component'; + export default Component.extend({ init() { return this._super(...arguments); } - });`, - `export default Route.extend({ + }); + `, + ` + import Route from '@ember/routing/route'; + export default Route.extend({ init() { return this._super(...arguments); } - });`, - `export default Controller.extend({ + }); + `, + ` + import Controller from '@ember/controller'; + export default Controller.extend({ init() { return this._super(...arguments); } - });`, - `export default Mixin.extend({ + }); + `, + ` + import Mixin from '@ember/object/mixin'; + export default Mixin.extend({ init() { return this._super(...arguments); } - });`, - `export default Service.extend({ + }); + `, + ` + import Service from '@ember/service'; + export default Service.extend({ init() { return this._super(...arguments); } - });`, - `export default Component({ - init() { - return this._super(...arguments); - } - });`, - `export default Route({ - init() { - return this._super(...arguments); - } - });`, - `export default Controller({ - init() { - return this._super(...arguments); - } - });`, - `export default Mixin({ - init() { - return this._super(...arguments); - } - });`, - `export default Service({ - init() { - return this._super(...arguments); - } - });`, - 'export default Component.extend();', - 'export default Route.extend();', - 'export default Controller.extend();', - 'export default Mixin.extend();', - 'export default Service.extend();', - `export default Component({ + }); + `, + ` + import Component from '@ember/component'; + export default Component.extend(); + `, + ` + import Route from '@ember/routing/route'; + export default Route.extend(); + `, + ` + import Controller from '@ember/controller'; + export default Controller.extend(); + `, + ` + import Mixin from '@ember/object/mixin'; + export default Mixin.extend(); + `, + ` + import Service from '@ember/service'; + export default Service.extend(); + `, + ` + import Component from '@ember/component'; + export default Component({ init() { this._super(...arguments); }, - });`, - `export default Route({ + }); + `, + ` + import Route from '@ember/routing/route'; + export default Route({ init() { this._super(...arguments); }, - });`, - `export default Controller({ + }); + `, + ` + import Controller from '@ember/controller'; + export default Controller({ init() { this._super(...arguments); }, - });`, - `export default Mixin({ + }); + `, + ` + import Mixin from '@ember/object/mixin'; + export default Mixin({ init() { this._super(...arguments); }, - });`, - `export default Service({ + }); + `, + ` + import Service from '@ember/service'; + export default Service({ init() { this._super(...arguments); }, - });`, - `export default Component({ + }); + `, + ` + import Component from '@ember/component'; + export default Component({ init: function() { this._super(...arguments); }, - });`, - `export default Route({ + }); + `, + ` + import Route from '@ember/routing/route'; + export default Route({ init: function() { this._super(...arguments); }, - });`, - `export default Controller({ + }); + `, + ` + import Controller from '@ember/controller'; + export default Controller({ init: function() { this._super(...arguments); }, - });`, - `export default Mixin({ + }); + `, + ` + import Mixin from '@ember/object/mixin'; + export default Mixin({ init: function() { this._super(...arguments); }, - });`, - `export default Service({ + }); + `, + ` + import Service from '@ember/service'; + export default Service({ init: function() { this._super(...arguments); }, - });`, - `export default Service({ + }); + `, + ` + import Service from '@ember/service'; + export default Service({ init - });`, + }); + `, ], invalid: [ { - code: `export default Component.extend({ - init() {}, - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + init() {}, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Component.extend({ - init() { - this.set('prop', 'value'); - }, - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + init() { + this.set('prop', 'value'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Component.extend({ - init() { - this.set('prop', 'value'); - this.set('prop2', 'value2'); - }, - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + init() { + this.set('prop', 'value'); + this.set('prop2', 'value2'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Route.extend({ - init() {}, - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + init() {}, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Route.extend({ - init() { - this.set('prop', 'value'); - }, - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + init() { + this.set('prop', 'value'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Route.extend({ - init() { - this.set('prop', 'value'); - this.set('prop2', 'value2'); - }, - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + init() { + this.set('prop', 'value'); + this.set('prop2', 'value2'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Controller.extend({ - init() {}, - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + init() {}, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Controller.extend({ - init() { - this.set('prop', 'value'); - }, - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + init() { + this.set('prop', 'value'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Controller.extend({ - init() { - this.set('prop', 'value'); - this.set('prop2', 'value2'); - }, - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + init() { + this.set('prop', 'value'); + this.set('prop2', 'value2'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Mixin.extend({ - init() {}, - });`, + code: ` + import Mixin from '@ember/object/mixin'; + export default Mixin.extend({ + init() {}, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Mixin.extend({ - init() { - this.set('prop', 'value'); - }, - });`, + code: ` + import Mixin from '@ember/object/mixin'; + export default Mixin.extend({ + init() { + this.set('prop', 'value'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Mixin.extend({ - init() { - this.set('prop', 'value'); - this.set('prop2', 'value2'); - }, - });`, + code: ` + import Mixin from '@ember/object/mixin'; + export default Mixin.extend({ + init() { + this.set('prop', 'value'); + this.set('prop2', 'value2'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Service.extend({ - init() {}, - });`, + code: ` + import Service from '@ember/service'; + export default Service.extend({ + init() {}, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Service.extend({ - init() { - this.set('prop', 'value'); - }, - });`, + code: ` + import Service from '@ember/service'; + export default Service.extend({ + init() { + this.set('prop', 'value'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Service.extend({ - init() { - this.set('prop', 'value'); - this.set('prop2', 'value2'); - }, - });`, + code: ` + import Service from '@ember/service'; + export default Service.extend({ + init() { + this.set('prop', 'value'); + this.set('prop2', 'value2'); + }, + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Component.extend({ - init() { - return; - } - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + init() { + return; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Route.extend({ - init() { - return; - } - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + init() { + return; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Controller.extend({ - init() { - return; - } - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + init() { + return; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Mixin.extend({ - init() { - return; - } - });`, + code: ` + import Mixin from '@ember/object/mixin'; + export default Mixin.extend({ + init() { + return; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Service.extend({ - init() { - return; - } - });`, + code: ` + import Service from '@ember/service'; + export default Service.extend({ + init() { + return; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Component({ - init() { - return; - } - });`, + code: ` + import Component from '@ember/component'; + export default Component.extend({ + init() { + return 'meh'; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Route({ - init() { - return; - } - });`, + code: ` + import Route from '@ember/routing/route'; + export default Route.extend({ + init() { + return 'meh'; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Controller({ - init() { - return; - } - });`, + code: ` + import Controller from '@ember/controller'; + export default Controller.extend({ + init() { + return 'meh'; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Mixin({ - init() { - return; - } - });`, + code: ` + import Mixin from '@ember/object/mixin'; + export default Mixin.extend({ + init() { + return 'meh'; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, { - code: `export default Service({ - init() { - return; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Component.extend({ - init() { - return 'meh'; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Route.extend({ - init() { - return 'meh'; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Controller.extend({ - init() { - return 'meh'; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Mixin.extend({ - init() { - return 'meh'; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Service.extend({ - init() { - return 'meh'; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Component({ - init() { - return 'meh'; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Route({ - init() { - return 'meh'; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Controller({ - init() { - return 'meh'; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Mixin({ - init() { - return 'meh'; - } - });`, - output: null, - errors: [{ message, line: 2 }], - }, - { - code: `export default Service({ - init() { - return 'meh'; - } - });`, + code: ` + import Service from '@ember/service'; + export default Service.extend({ + init() { + return 'meh'; + } + }); + `, output: null, - errors: [{ message, line: 2 }], + errors: [{ message, line: 4 }], }, ], }); diff --git a/tests/lib/rules/require-tagless-components.js b/tests/lib/rules/require-tagless-components.js index e9c9496b40..66c7fb8239 100644 --- a/tests/lib/rules/require-tagless-components.js +++ b/tests/lib/rules/require-tagless-components.js @@ -56,6 +56,14 @@ ruleTester.run('require-tagless-components', rule, { tagName = 'some-non-empty-value'; } `, + ` + import Service from '@ember/service'; + export default Service.extend({}); + `, + ` + import Service from '@ember/service'; + export default class MyService extends Service {} + `, ], invalid: [ { diff --git a/tests/lib/utils/ember-test.js b/tests/lib/utils/ember-test.js index ffe92b96f8..d664ebca41 100644 --- a/tests/lib/utils/ember-test.js +++ b/tests/lib/utils/ember-test.js @@ -100,55 +100,73 @@ describe('isTestFile', () => { describe('isEmberCoreModule', () => { it('should check if current file is a component', () => { const context = new FauxContext( - 'CustomComponent.extend()', + ` + import CustomComponent from '@ember/component'; + CustomComponent.extend() + `, 'example-app/components/path/to/some-component.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberCoreModule(context, node, 'Component')).toBeTruthy(); }); it('should check if current file is a component', () => { const context = new FauxContext( - 'Component.extend()', + ` + import CustomComponent from '@ember/component'; + CustomComponent.extend() + `, 'example-app/some-twisted-path/some-component.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberCoreModule(context, node, 'Component')).toBeTruthy(); }); it('should check if current file is a controller', () => { const context = new FauxContext( - 'CustomController.extend()', + ` + import CustomController from '@ember/controller'; + CustomController.extend() + `, 'example-app/controllers/path/to/some-controller.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberCoreModule(context, node, 'Controller')).toBeTruthy(); }); it('should check if current file is a controller', () => { const context = new FauxContext( - 'Controller.extend()', + ` + import CustomController from '@ember/controller'; + CustomController.extend() + `, 'example-app/some-twisted-path/some-controller.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberCoreModule(context, node, 'Controller')).toBeTruthy(); }); it('should check if current file is a route', () => { const context = new FauxContext( - 'CustomRoute.extend()', + ` + import CustomRoute from '@ember/routing/route'; + CustomRoute.extend() + `, 'example-app/routes/path/to/some-route.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberCoreModule(context, node, 'Route')).toBeTruthy(); }); it('should check if current file is a route', () => { const context = new FauxContext( - 'Route.extend()', + ` + import Route from '@ember/routing/route'; + Route.extend() + `, 'example-app/some-twisted-path/some-route.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberCoreModule(context, node, 'Route')).toBeTruthy(); }); @@ -170,8 +188,11 @@ describe('isEmberComponent', () => { }); it('it should detect Component when using local module Component', () => { - const context = new FauxContext('Component.extend()'); - const node = context.ast.body[0].expression; + const context = new FauxContext(` + import Component from '@ember/component'; + Component.extend() + `); + const node = context.ast.body[1].expression; expect(emberUtils.isEmberComponent(context, node)).toBeTruthy(); }); @@ -203,10 +224,13 @@ describe('isEmberComponent', () => { it('it should detect Component when file path is provided', () => { const context = new FauxContext( - 'CustomComponent.extend()', + ` + import CustomComponent from '@ember/component'; + CustomComponent.extend() + `, 'example-app/components/path/to/some-component.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberComponent(context, node)).toBeTruthy(); }); @@ -230,8 +254,11 @@ describe('isEmberController', () => { }); it('it should detect Controller when using local module Controller', () => { - const context = new FauxContext('Controller.extend()'); - const node = context.ast.body[0].expression; + const context = new FauxContext(` + import Controller from '@ember/controller'; + Controller.extend() + `); + const node = context.ast.body[1].expression; expect(emberUtils.isEmberController(context, node)).toBeTruthy(); }); @@ -263,10 +290,13 @@ describe('isEmberController', () => { it('it should detect Controller when file path is provided', () => { const context = new FauxContext( - 'CustomController.extend()', + ` + import CustomController from '@ember/controller'; + CustomController.extend() + `, 'example-app/controllers/path/to/some-feature.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberController(context, node)).toBeTruthy(); }); @@ -290,8 +320,11 @@ describe('isEmberRoute', () => { }); it('should detect Route when using local module Route', () => { - const context = new FauxContext('Route.extend()'); - const node = context.ast.body[0].expression; + const context = new FauxContext(` + import Route from '@ember/routing/route'; + Route.extend() + `); + const node = context.ast.body[1].expression; expect(emberUtils.isEmberRoute(context, node)).toBeTruthy(); }); @@ -323,10 +356,13 @@ describe('isEmberRoute', () => { it('it should detect Route when file path is provided', () => { const context = new FauxContext( - 'CustomRoute.extend()', + ` + import CustomRoute from '@ember/routing/route'; + CustomRoute.extend() + `, 'example-app/routes/path/to/some-feature.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberRoute(context, node)).toBeTruthy(); }); @@ -384,8 +420,11 @@ describe('isEmberService', () => { }); it('should detect Service when using local module Service', () => { - const context = new FauxContext('Service.extend()'); - const node = context.ast.body[0].expression; + const context = new FauxContext(` + import Service from '@ember/service'; + Service.extend() + `); + const node = context.ast.body[1].expression; expect(emberUtils.isEmberService(context, node)).toBeTruthy(); }); @@ -417,10 +456,13 @@ describe('isEmberService', () => { it('it should detect Service when file path is provided', () => { const context = new FauxContext( - 'CustomService.extend()', + ` + import CustomService from '@ember/service'; + CustomService.extend() + `, 'example-app/services/path/to/some-feature.js' ); - const node = context.ast.body[0].expression; + const node = context.ast.body[1].expression; expect(emberUtils.isEmberService(context, node)).toBeTruthy(); }); @@ -449,8 +491,11 @@ describe('isEmberArrayProxy', () => { }); it('should detect when using local module', () => { - const context = new FauxContext('ArrayProxy.extend()'); - const node = context.ast.body[0].expression; + const context = new FauxContext(` + import ArrayProxy from '@ember/array/proxy'; + ArrayProxy.extend() + `); + const node = context.ast.body[1].expression; expect(emberUtils.isEmberArrayProxy(context, node)).toBeTruthy(); }); @@ -502,8 +547,11 @@ describe('isEmberObjectProxy', () => { }); it('should detect when using local module', () => { - const context = new FauxContext('ObjectProxy.extend()'); - const node = context.ast.body[0].expression; + const context = new FauxContext(` + import ObjectProxy from '@ember/object/proxy'; + ObjectProxy.extend() + `); + const node = context.ast.body[1].expression; expect(emberUtils.isEmberObjectProxy(context, node)).toBeTruthy(); }); @@ -559,12 +607,6 @@ describe('isEmberProxy', () => { const node = context.ast.body[1]; expect(emberUtils.isEmberProxy(context, node)).toBeTruthy(); }); - - it('should not detect random code', () => { - const context = new FauxContext('someFunctionCall();'); - const node = context.ast.body[0].expression; - expect(emberUtils.isEmberProxy(context, node)).toBeFalsy(); - }); }); describe('isInjectedServiceProp', () => { diff --git a/tests/lib/utils/utils/get-source-module-name-for-identifier-test.js b/tests/lib/utils/import-info/get-source-module-name-for-identifier-test.js similarity index 98% rename from tests/lib/utils/utils/get-source-module-name-for-identifier-test.js rename to tests/lib/utils/import-info/get-source-module-name-for-identifier-test.js index b8fc03b9cc..250b6fe2a8 100644 --- a/tests/lib/utils/utils/get-source-module-name-for-identifier-test.js +++ b/tests/lib/utils/import-info/get-source-module-name-for-identifier-test.js @@ -1,4 +1,4 @@ -const { getSourceModuleNameForIdentifier } = require('../../../../lib/utils/utils'); +const { getSourceModuleNameForIdentifier } = require('../../../../lib/utils/import-info'); const { FauxContext } = require('../../../helpers/faux-context'); const babelEslint = require('babel-eslint'); diff --git a/tests/lib/utils/import-info/is-default-import.js b/tests/lib/utils/import-info/is-default-import.js new file mode 100644 index 0000000000..aaf07ab981 --- /dev/null +++ b/tests/lib/utils/import-info/is-default-import.js @@ -0,0 +1,63 @@ +const { isDefaultImport } = require('../../../../lib/utils/import-info'); +const { FauxContext } = require('../../../helpers/faux-context'); +const babelEslint = require('babel-eslint'); + +test('when the identifier is not imported', () => { + const context = new FauxContext(` + Foo; + `); + + const node = { name: 'Foo', type: 'Identifier' }; + + expect(isDefaultImport(context, node)).toEqual(false); +}); + +describe('when the identifier is imported', () => { + test('as a default export', () => { + const context = new FauxContext(` + import Foo from 'bar'; + + Foo; + `); + + const node = { name: 'Foo', type: 'Identifier' }; + + expect(isDefaultImport(context, node)).toEqual(true); + }); + + test('as a named export', () => { + const context = new FauxContext(` + import { Foo } from 'bar'; + + Foo; + `); + + const node = { name: 'Foo', type: 'Identifier' }; + + expect(isDefaultImport(context, node)).toEqual(false); + }); + + test('when aliasing a named export', () => { + const context = new FauxContext(` + import { SomeOtherThing as Foo } from 'bar'; + + Foo; + `); + + const node = { name: 'Foo', type: 'Identifier' }; + + expect(isDefaultImport(context, node)).toEqual(false); + }); + + test('Some.Long.Chained.Path.extend', () => { + const context = new FauxContext(` + import Some from 'some-path'; + + Some.Long.Chained.Path.extend(); + `); + + const node = babelEslint.parse('Some.Long.Chained.Path.extend({})').body[0].expression.callee; + + expect(isDefaultImport(context, node)).toEqual(true); + }); +});