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

eslint-plugin-ember

Package Overview
Dependencies
Maintainers
6
Versions
189
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-ember - npm Package Compare versions

Comparing version 10.4.0 to 10.4.1

5

lib/rules/alias-model-in-controller.js

@@ -31,2 +31,5 @@ 'use strict';

const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -38,3 +41,3 @@ CallExpression(node) {

const properties = ember.getModuleProperties(node);
const properties = ember.getModuleProperties(node, scopeManager);
let aliasPresent = false;

@@ -41,0 +44,0 @@

@@ -83,2 +83,5 @@ 'use strict';

const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -96,3 +99,3 @@ CallExpression(node) {

const properties = ember.getModuleProperties(node);
const properties = ember.getModuleProperties(node, scopeManager);

@@ -99,0 +102,0 @@ for (const property of properties.filter(

@@ -30,2 +30,5 @@ 'use strict';

const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -39,3 +42,3 @@ CallExpression(node) {

const properties = ember.getModuleProperties(node);
const properties = ember.getModuleProperties(node, scopeManager);

@@ -42,0 +45,0 @@ for (const property of properties) {

@@ -22,2 +22,5 @@ const ember = require('../utils/ember');

create: (context) => {
const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
function reportActionsProp(properties) {

@@ -38,3 +41,3 @@ const actionsProp = properties.find((property) => ember.isActionsProp(property));

if (inClassWhichCanContainActions(context, node)) {
reportActionsProp(ember.getModuleProperties(node));
reportActionsProp(ember.getModuleProperties(node, scopeManager));
}

@@ -41,0 +44,0 @@ },

26

lib/rules/no-classic-classes.js

@@ -5,4 +5,3 @@ 'use strict';

const { startsWithThisExpression } = require('../utils/utils');
const { isObjectExpression } = require('../utils/types');
const { findVariable } = require('eslint-utils');
const { getNodeOrNodeFromVariable } = require('../utils/utils');

@@ -18,23 +17,4 @@ const ERROR_MESSAGE_NO_CLASSIC_CLASSES =

return node.arguments.some((arg) => {
if (isObjectExpression(arg)) {
return true;
}
if (arg.type === 'Identifier') {
// Check if a variable is provided that was initialized as an object.
const variable = findVariable(scopeManager.acquire(arg) || scopeManager.globalScope, arg);
if (
variable &&
variable.defs &&
variable.defs[0] &&
variable.defs[0].node &&
variable.defs[0].node.type === 'VariableDeclarator' &&
variable.defs[0].node.init &&
variable.defs[0].node.init.type === 'ObjectExpression'
) {
return true;
}
}
return false;
const resultingNode = getNodeOrNodeFromVariable(arg, scopeManager);
return resultingNode && resultingNode.type === 'ObjectExpression';
});

@@ -41,0 +21,0 @@ }

const ember = require('../utils/ember');
const types = require('../utils/types');
const utils = require('../utils/utils');
const assert = require('assert');

@@ -23,2 +24,5 @@

create: (context) => {
const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -37,3 +41,4 @@ ClassDeclaration(node) {

ember.isEmberController(context, node) &&
(node.arguments.length === 0 || !callExpressionClassHasProperty(node, 'queryParams'))
(node.arguments.length === 0 ||
!callExpressionClassHasProperty(node, 'queryParams', scopeManager))
) {

@@ -60,11 +65,17 @@ context.report(node, ERROR_MESSAGE);

function callExpressionClassHasProperty(callExpression, propertyName) {
function callExpressionClassHasProperty(callExpression, propertyName, scopeManager) {
assert(types.isCallExpression(callExpression));
return (
callExpression.arguments.length > 0 &&
types.isObjectExpression(callExpression.arguments[callExpression.arguments.length - 1]) &&
callExpression.arguments[callExpression.arguments.length - 1].properties.some(
(prop) => types.isIdentifier(prop.key) && prop.key.name === propertyName
)
callExpression.arguments.some((arg) => {
const resultingNode = utils.getNodeOrNodeFromVariable(arg, scopeManager);
return (
resultingNode &&
resultingNode.type === 'ObjectExpression' &&
resultingNode.properties.some(
(prop) => types.isIdentifier(prop.key) && prop.key.name === propertyName
)
);
})
);
}

@@ -31,2 +31,5 @@ 'use strict';

const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -38,3 +41,3 @@ CallExpression(node) {

const allProperties = ember.getModuleProperties(node);
const allProperties = ember.getModuleProperties(node, scopeManager);
const isDSAttr = allProperties.filter((property) =>

@@ -41,0 +44,0 @@ ember.isModule(property.value, 'attr', 'DS')

@@ -143,2 +143,5 @@ 'use strict';

const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
// Skip mirage directory

@@ -181,3 +184,3 @@ if (emberUtils.isMirageConfig(filename)) {

}
if (emberUtils.isEmberObjectImplementingUnknownProperty(node)) {
if (emberUtils.isEmberObjectImplementingUnknownProperty(node, scopeManager)) {
currentClassWithUnknownPropertyMethod = node; // Keep track of being inside an object implementing `unknownProperty`.

@@ -196,3 +199,3 @@ }

}
if (emberUtils.isEmberObjectImplementingUnknownProperty(node)) {
if (emberUtils.isEmberObjectImplementingUnknownProperty(node, scopeManager)) {
currentClassWithUnknownPropertyMethod = node;

@@ -199,0 +202,0 @@ }

@@ -65,2 +65,5 @@ 'use strict';

const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -72,3 +75,5 @@ CallExpression(node) {

const propertiesWithOnCalls = ember.getModuleProperties(node).filter(isOnCall);
const propertiesWithOnCalls = ember
.getModuleProperties(node, scopeManager)
.filter(isOnCall);

@@ -75,0 +80,0 @@ if (propertiesWithOnCalls.length > 0) {

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

const types = require('../utils/types');
const { getImportIdentifier } = require('../utils/import');

@@ -61,6 +62,18 @@ //------------------------------------------------------------------------------

let importedInjectName;
let importedEmberName;
return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');
}
if (node.source.value === '@ember/service') {
importedInjectName =
importedInjectName || getImportIdentifier(node, '@ember/service', 'inject');
}
},
Property(node) {
if (
emberUtils.isInjectedServiceProp(node) &&
emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName) &&
node.value.arguments.length > 0 &&

@@ -67,0 +80,0 @@ node.value.arguments[0].value === ROUTING_SERVICE_NAME

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

const decoratorUtils = require('../utils/decorators');
const { getImportIdentifier } = require('../utils/import');

@@ -16,3 +17,3 @@ const DEFAULT_ERROR_MESSAGE = 'Injecting this service is not allowed from this file.';

description: 'disallow injecting certain services under certain paths',
category: 'Miscellaneous',
category: 'Services',
url:

@@ -92,3 +93,15 @@ 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/no-restricted-service-injections.md',

let importedInjectName;
let importedEmberName;
return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');
}
if (node.source.value === '@ember/service') {
importedInjectName =
importedInjectName || getImportIdentifier(node, '@ember/service', 'inject');
}
},
// Handles:

@@ -98,3 +111,3 @@ // * myService: service()

Property(node) {
if (!emberUtils.isInjectedServiceProp(node)) {
if (!emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName)) {
return;

@@ -127,3 +140,3 @@ }

ClassProperty(node) {
if (!emberUtils.isInjectedServiceProp(node)) {
if (!emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName)) {
return;

@@ -130,0 +143,0 @@ }

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

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

@@ -61,2 +62,5 @@ const ROOT_PATH_TRIM_REGEX = /\/{2,}/g;

const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -68,3 +72,3 @@ CallExpression(node) {

const routeInfo = getRouteInfo(node);
const routeInfo = getRouteInfo(node, scopeManager);
if (!isValidRouteInfo(routeInfo)) {

@@ -104,4 +108,4 @@ return;

function getRouteInfo(node) {
const basePath = getRouteBasePath(node);
function getRouteInfo(node, scopeManager) {
const basePath = getRouteBasePath(node, scopeManager);
if (basePath.normalizedPath === null) {

@@ -111,3 +115,3 @@ return null;

const parentRoutes = getParentRoutesPaths(node);
const parentRoutes = getParentRoutesPaths(node, scopeManager);
const notSupportedParentRoutePathArguments = parentRoutes.find((routePathInfo) => {

@@ -146,6 +150,11 @@ return routePathInfo.normalizedPath === null;

function getRouteBasePath(node) {
function getRouteBasePath(node, scopeManager) {
let routePathInfo = getRouteName(node);
if (hasPathProperty(node)) {
const pathOptionNode = getPropertyByKeyName(node.arguments[1], 'path');
const optionsNode =
node.arguments.length >= 2 && getNodeOrNodeFromVariable(node.arguments[1], scopeManager);
const pathOptionNode =
optionsNode &&
optionsNode.type === 'ObjectExpression' &&
getPropertyByKeyName(optionsNode, 'path');
if (pathOptionNode) {
routePathInfo = getNodeValue(pathOptionNode.value);

@@ -165,3 +174,3 @@ }

function getParentRoutesPaths(node) {
function getParentRoutesPaths(node, scopeManager) {
const parentNode = node.parent;

@@ -171,3 +180,3 @@ let stack = [];

if (ember.isRoute(parentNode)) {
stack.push(getRouteBasePath(parentNode));
stack.push(getRouteBasePath(parentNode, scopeManager));
}

@@ -179,12 +188,2 @@ stack = [...stack, ...getParentRoutesPaths(parentNode)];

function hasPathProperty(node) {
return (
types.isObjectExpression(node.arguments[1]) && hasPropertyWithKeyName(node.arguments[1], 'path')
);
}
function hasPropertyWithKeyName(objectExpression, keyName) {
return getPropertyByKeyName(objectExpression, keyName) !== undefined;
}
function getPropertyByKeyName(objectExpression, keyName) {

@@ -191,0 +190,0 @@ return objectExpression.properties.find(

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

const fixerUtils = require('../utils/fixer');
const { getNodeOrNodeFromVariable } = require('../utils/utils');

@@ -31,2 +32,5 @@ //------------------------------------------------------------------------------

create(context) {
const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -38,5 +42,8 @@ CallExpression(node) {

let optionsNode;
const hasExplicitPathOption =
types.isObjectExpression(node.arguments[1]) &&
hasPropertyWithKeyName(node.arguments[1], 'path');
node.arguments.length >= 2 &&
(optionsNode = getNodeOrNodeFromVariable(node.arguments[1], scopeManager)) &&
optionsNode.type === 'ObjectExpression' &&
hasPropertyWithKeyName(optionsNode, 'path');
if (!hasExplicitPathOption) {

@@ -46,3 +53,3 @@ return;

const pathOptionNode = getPropertyByKeyName(node.arguments[1], 'path');
const pathOptionNode = getPropertyByKeyName(optionsNode, 'path');
const pathOptionValue = pathOptionNode.value.value;

@@ -58,5 +65,12 @@ const routeName = node.arguments[0].value;

if (optionsNode.parent.type === 'VariableDeclarator') {
// When the options object is a separate variable.
return optionsNode.properties.length === 1
? fixer.remove(pathOptionNode)
: fixerUtils.removeCommaSeparatedNode(pathOptionNode, sourceCode, fixer);
}
// If the `path` option is the only property in the object, remove the entire object.
const shouldRemoveObject = node.arguments[1].properties.length === 1;
const nodeToRemove = shouldRemoveObject ? node.arguments[1] : pathOptionNode;
const shouldRemoveObject = optionsNode.properties.length === 1;
const nodeToRemove = shouldRemoveObject ? optionsNode : pathOptionNode;

@@ -63,0 +77,0 @@ return fixerUtils.removeCommaSeparatedNode(nodeToRemove, sourceCode, fixer);

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

const emberUtils = require('../utils/ember');
const { getImportIdentifier } = require('../utils/import');

@@ -31,6 +32,18 @@ //------------------------------------------------------------------------------

create(context) {
let importedInjectName;
let importedEmberName;
return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');
}
if (node.source.value === '@ember/service') {
importedInjectName =
importedInjectName || getImportIdentifier(node, '@ember/service', 'inject');
}
},
Property(node) {
if (
!emberUtils.isInjectedServiceProp(node) ||
!emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName) ||
node.value.arguments.length !== 1 ||

@@ -58,3 +71,3 @@ !types.isStringLiteral(node.value.arguments[0])

if (
!emberUtils.isInjectedServiceProp(node) ||
!emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName) ||
node.decorators.length !== 1 ||

@@ -61,0 +74,0 @@ !types.isCallExpression(node.decorators[0].expression) ||

@@ -41,5 +41,4 @@ 'use strict';

main:
'The service `{{name}}` is not referenced in this JS file, but it may still be referenced in the corresponding HBS file. Please remove this service injection if it is not being used within the HBS file.',
removeServiceInjection:
'Remove the service injection if not used within the corresponding HBS file.',
'The service `{{name}}` is not referenced in this JS file and might be unused (note: it could still be used in a corresponding handlebars template file, mixin, or parent/child class).',
removeServiceInjection: 'Remove the service injection.',
},

@@ -56,2 +55,5 @@ },

let importedGetPropertiesName;
let importedInjectName;
let importedObserverName;
let importedObservesName;
const macros = getMacros();

@@ -78,3 +80,3 @@ const importedMacros = {};

const { services, uses } = currentClass;
if (!services || !uses) {
if (Object.keys(services).length === 0) {
return;

@@ -119,3 +121,6 @@ }

getImportIdentifier(node, '@ember/object', 'getProperties');
} else if (node.source.value === '@ember/object/computed') {
importedObserverName =
importedObserverName || getImportIdentifier(node, '@ember/object', 'observer');
}
if (node.source.value === '@ember/object/computed') {
for (const spec of node.specifiers) {

@@ -128,3 +133,13 @@ const name = spec.imported.name;

}
} else if (node.source.value === 'ember') {
}
if (node.source.value === '@ember/service') {
importedInjectName =
importedInjectName || getImportIdentifier(node, '@ember/service', 'inject');
}
if (node.source.value === '@ember-decorators/object') {
importedObservesName =
importedObservesName ||
getImportIdentifier(node, '@ember-decorators/object', 'observes');
}
if (node.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');

@@ -153,12 +168,10 @@ }

) {
if (node.callee.property) {
// Ember.computed.or(), computed.or()
const macroName = node.callee.property.name;
if (macros.includes(macroName)) {
for (
let idx = 0;
idx < MACROS_TO_TRACKED_ARGUMENT_COUNT[macroName] && idx < node.arguments.length;
idx++
) {
const elem = node.arguments[idx];
// Ember.computed(), Ember.computed.or(), computed.or()
if (types.isMemberExpression(node.callee)) {
if (
types.isIdentifier(node.callee.object) &&
node.callee.object.name === importedEmberName
) {
// Ember.computed()
for (const elem of node.arguments) {
if (types.isStringLiteral(elem)) {

@@ -169,5 +182,22 @@ const name = splitValue(elem.value);

}
} else if (types.isIdentifier(node.callee.property)) {
// Ember.computed.or(), computed.or()
const macroName = node.callee.property.name;
if (macros.includes(macroName)) {
for (
let idx = 0;
idx < MACROS_TO_TRACKED_ARGUMENT_COUNT[macroName] &&
idx < node.arguments.length;
idx++
) {
const elem = node.arguments[idx];
if (types.isStringLiteral(elem)) {
const name = splitValue(elem.value);
currentClass.uses.add(name);
}
}
}
}
} else {
// Ember.computed(), computed()
// computed()
for (const elem of node.arguments) {

@@ -232,3 +262,25 @@ if (types.isStringLiteral(elem)) {

}
} else if (calleeName === importedObserverName) {
// observer('foo', ...)
for (const elem of node.arguments) {
if (types.isStringLiteral(elem)) {
const name = splitValue(elem.value);
currentClass.uses.add(name);
}
}
}
} else if (
types.isMemberExpression(node.callee) &&
types.isIdentifier(node.callee.object) &&
node.callee.object.name === importedEmberName &&
types.isIdentifier(node.callee.property) &&
node.callee.property.name === 'observer'
) {
// Ember.observer('foo', ...)
for (const elem of node.arguments) {
if (types.isStringLiteral(elem)) {
const name = splitValue(elem.value);
currentClass.uses.add(name);
}
}
}

@@ -249,6 +301,35 @@ }

},
// @observes('foo', ...)
Decorator(node) {
// If Ember and Ember.inject weren't imported OR observes wasn't imported, skip out early
if ((!importedEmberName && !importedInjectName) || !importedObservesName) {
return;
}
const currentClass = classStack.peek();
if (
currentClass &&
emberUtils.isObserverDecorator(node, importedObservesName) &&
types.isCallExpression(node.expression)
) {
for (const elem of node.expression.arguments) {
if (types.isStringLiteral(elem)) {
const name = splitValue(elem.value);
currentClass.uses.add(name);
}
}
}
},
// foo: service(...)
Property(node) {
// If Ember and Ember.inject weren't imported, skip out early
if (!importedEmberName && !importedInjectName) {
return;
}
const currentClass = classStack.peek();
if (currentClass && emberUtils.isInjectedServiceProp(node)) {
if (
currentClass &&
emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName)
) {
const name = node.key.name;

@@ -260,4 +341,12 @@ currentClass.services[name] = node;

ClassProperty(node) {
// If Ember and Ember.inject weren't imported, skip out early
if (!importedEmberName && !importedInjectName) {
return;
}
const currentClass = classStack.peek();
if (currentClass && emberUtils.isInjectedServiceProp(node)) {
if (
currentClass &&
emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName)
) {
const name = node.key.name;

@@ -264,0 +353,0 @@ currentClass.services[name] = node;

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

const propOrder = require('../utils/property-order');
const { getImportIdentifier } = require('../utils/import');

@@ -89,3 +90,18 @@ const reportUnorderedProperties = propOrder.reportUnorderedProperties;

let importedInjectName;
let importedEmberName;
const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');
}
if (node.source.value === '@ember/service') {
importedInjectName =
importedInjectName || getImportIdentifier(node, '@ember/service', 'inject');
}
},
CallExpression(node) {

@@ -96,3 +112,11 @@ if (!ember.isEmberComponent(context, node)) {

reportUnorderedProperties(node, context, 'component', order);
reportUnorderedProperties(
node,
context,
'component',
order,
importedEmberName,
importedInjectName,
scopeManager
);
},

@@ -99,0 +123,0 @@ };

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

const propOrder = require('../utils/property-order');
const { getImportIdentifier } = require('../utils/import');

@@ -61,3 +62,18 @@ const reportUnorderedProperties = propOrder.reportUnorderedProperties;

let importedInjectName;
let importedEmberName;
const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');
}
if (node.source.value === '@ember/service') {
importedInjectName =
importedInjectName || getImportIdentifier(node, '@ember/service', 'inject');
}
},
CallExpression(node) {

@@ -68,3 +84,11 @@ if (!ember.isEmberController(context, node)) {

reportUnorderedProperties(node, context, 'controller', order);
reportUnorderedProperties(
node,
context,
'controller',
order,
importedEmberName,
importedInjectName,
scopeManager
);
},

@@ -71,0 +95,0 @@ };

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

const propOrder = require('../utils/property-order');
const { getImportIdentifier } = require('../utils/import');

@@ -56,3 +57,18 @@ const reportUnorderedProperties = propOrder.reportUnorderedProperties;

let importedInjectName;
let importedEmberName;
const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');
}
if (node.source.value === '@ember/service') {
importedInjectName =
importedInjectName || getImportIdentifier(node, '@ember/service', 'inject');
}
},
CallExpression(node) {

@@ -63,3 +79,11 @@ if (!ember.isDSModel(node, filePath)) {

reportUnorderedProperties(node, context, 'model', order);
reportUnorderedProperties(
node,
context,
'model',
order,
importedEmberName,
importedInjectName,
scopeManager
);
},

@@ -66,0 +90,0 @@ };

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

const propOrder = require('../utils/property-order');
const { getImportIdentifier } = require('../utils/import');

@@ -84,3 +85,18 @@ const reportUnorderedProperties = propOrder.reportUnorderedProperties;

let importedInjectName;
let importedEmberName;
const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(node, 'ember');
}
if (node.source.value === '@ember/service') {
importedInjectName =
importedInjectName || getImportIdentifier(node, '@ember/service', 'inject');
}
},
CallExpression(node) {

@@ -90,3 +106,11 @@ if (!ember.isEmberRoute(context, node)) {

}
reportUnorderedProperties(node, context, 'route', order);
reportUnorderedProperties(
node,
context,
'route',
order,
importedEmberName,
importedInjectName,
scopeManager
);
},

@@ -93,0 +117,0 @@ };

@@ -140,7 +140,19 @@ 'use strict';

let importedEmberName;
let importedInjectName;
new Traverser().traverse(node, {
enter(child) {
if (types.isImportDeclaration(child)) {
if (child.source.value === 'ember') {
importedEmberName = importedEmberName || getImportIdentifier(child, 'ember');
}
if (child.source.value === '@ember/service') {
importedInjectName =
importedInjectName || getImportIdentifier(child, '@ember/service', 'inject');
}
}
if (
(types.isProperty(child) || types.isClassProperty(child)) &&
emberUtils.isInjectedServiceProp(child) &&
emberUtils.isInjectedServiceProp(child, importedEmberName, importedInjectName) &&
types.isIdentifier(child.key)

@@ -147,0 +159,0 @@ ) {

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

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

@@ -105,2 +106,5 @@ const ERROR_MESSAGE_REQUIRE_TAGLESS_COMPONENTS =

create(context) {
const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -121,4 +125,6 @@ // Handle classic components

for (const arg of callExpression.arguments) {
const resultingNode = getNodeOrNodeFromVariable(arg, scopeManager);
// Ignore anything other than an object literal, since Mixins can be in here too
if (!isObjectExpression(arg)) {
if (!isObjectExpression(resultingNode)) {
continue;

@@ -129,5 +135,5 @@ }

if ((tagNameNode = getNonEmptyTagNameInObjectExpression(arg))) {
if ((tagNameNode = getNonEmptyTagNameInObjectExpression(resultingNode))) {
context.report(tagNameNode, ERROR_MESSAGE_REQUIRE_TAGLESS_COMPONENTS);
} else if (hasNoTagNameInObjectExpression(arg)) {
} else if (hasNoTagNameInObjectExpression(resultingNode)) {
context.report(callExpression, ERROR_MESSAGE_REQUIRE_TAGLESS_COMPONENTS);

@@ -134,0 +140,0 @@ }

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

const kebabCase = require('lodash.kebabcase');
const { getNodeOrNodeFromVariable } = require('../utils/utils');

@@ -36,2 +37,5 @@ //------------------------------------------------------------------------------

create(context) {
const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -47,8 +51,10 @@ CallExpression(node) {

let optionsNode;
const hasExplicitPathOption =
node.arguments.length >= 2 &&
types.isObjectExpression(node.arguments[1]) &&
hasPropertyWithKeyName(node.arguments[1], 'path');
(optionsNode = getNodeOrNodeFromVariable(node.arguments[1], scopeManager)) &&
optionsNode.type === 'ObjectExpression' &&
hasPropertyWithKeyName(optionsNode, 'path');
const pathValueNode = hasExplicitPathOption
? getPropertyByKeyName(node.arguments[1], 'path').value
? getPropertyByKeyName(optionsNode, 'path').value
: node.arguments[0];

@@ -55,0 +61,0 @@

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

const { snakeCase } = require('snake-case');
const { getNodeOrNodeFromVariable } = require('../utils/utils');

@@ -55,2 +56,5 @@ //------------------------------------------------------------------------------

const sourceCode = context.getSourceCode();
const { scopeManager } = sourceCode;
return {

@@ -62,5 +66,9 @@ CallExpression(node) {

const routeOptions = types.isObjectExpression(node.arguments[1])
? node.arguments[1]
: false;
let optionsNode;
const routeOptions =
node.arguments.length >= 2 &&
(optionsNode = getNodeOrNodeFromVariable(node.arguments[1], scopeManager)) &&
optionsNode.type === 'ObjectExpression'
? optionsNode
: false;

@@ -67,0 +75,0 @@ if (routeOptions) {

@@ -9,2 +9,4 @@ 'use strict';

const decoratorUtils = require('../utils/decorators');
const { getNodeOrNodeFromVariable } = require('../utils/utils');
const { flatMap } = require('../utils/javascript');

@@ -190,6 +192,16 @@ module.exports = {

// jQuery has an `extend` function and we want to avoid mistaking it for an extended object.
// TODO: ideally, this would check the actual name that jQuery is imported under, but there's a lot of plumbing needed for that.
const COMMON_JQUERY_NAMES = new Set(['$', 'jQuery']);
function isExtendObject(node) {
// Check for:
// * foo.extend();
// * foo['extend']();
return (
node.callee.property &&
(node.callee.property.name === 'extend' || node.callee.property.value === 'extend')
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
((node.callee.property.type === 'Identifier' && node.callee.property.name === 'extend') ||
(node.callee.property.type === 'Literal' && node.callee.property.value === 'extend')) &&
!(node.callee.object.type === 'Identifier' && COMMON_JQUERY_NAMES.has(node.callee.object.name))
);

@@ -304,4 +316,25 @@ }

function isInjectedServiceProp(node) {
return isPropOfType(node, 'service') || isPropOfType(node, 'inject');
/**
* Checks if a node is a service injection. Looks for:
* * service()
* * Ember.inject.service()
* @param {node} node
* @param {string} importedEmberName name that `Ember` is imported under
* @param {string} importedInjectName name that `inject` is imported under
* @returns
*/
function isInjectedServiceProp(node, importedEmberName, importedInjectName) {
return (
isPropOfType(node, importedInjectName) ||
(types.isProperty(node) &&
types.isCallExpression(node.value) &&
types.isMemberExpression(node.value.callee) &&
types.isMemberExpression(node.value.callee.object) &&
types.isIdentifier(node.value.callee.object.object) &&
node.value.callee.object.object.name === importedEmberName &&
types.isIdentifier(node.value.callee.object.property) &&
node.value.callee.object.property.name === 'inject' &&
types.isIdentifier(node.value.callee.property) &&
node.value.callee.property.name === 'service')
);
}

@@ -533,5 +566,9 @@

function getModuleProperties(module) {
const firstObjectExpressionNode = utils.findNodes(module.arguments, 'ObjectExpression')[0];
return firstObjectExpressionNode ? firstObjectExpressionNode.properties : [];
function getModuleProperties(moduleNode, scopeManager) {
return flatMap(moduleNode.arguments, (arg) => {
const resultingNode = getNodeOrNodeFromVariable(arg, scopeManager);
return resultingNode && resultingNode.type === 'ObjectExpression'
? resultingNode.properties
: [];
});
}

@@ -661,3 +698,3 @@

function isEmberObjectImplementingUnknownProperty(node) {
function isEmberObjectImplementingUnknownProperty(node, scopeManager) {
if (types.isCallExpression(node)) {

@@ -668,3 +705,3 @@ if (!isExtendObject(node) && !isReopenObject(node)) {

// Classic class.
const properties = getModuleProperties(node);
const properties = getModuleProperties(node, scopeManager);
return properties.some(

@@ -671,0 +708,0 @@ (property) => types.isIdentifier(property.key) && property.key.name === 'unknownProperty'

@@ -55,4 +55,4 @@ 'use strict';

// eslint-disable-next-line complexity
function determinePropertyType(node, parentType, ORDER) {
if (ember.isInjectedServiceProp(node)) {
function determinePropertyType(node, parentType, ORDER, importedEmberName, importedInjectName) {
if (ember.isInjectedServiceProp(node, importedEmberName, importedInjectName)) {
return 'service';

@@ -192,3 +192,11 @@ }

function reportUnorderedProperties(node, context, parentType, ORDER) {
function reportUnorderedProperties(
node,
context,
parentType,
ORDER,
importedEmberName,
importedInjectName,
scopeManager
) {
let maxOrder = -1;

@@ -200,6 +208,12 @@ const firstPropertyOfType = {};

? node.body.body
: ember.getModuleProperties(node);
: ember.getModuleProperties(node, scopeManager);
for (const property of properties) {
const type = determinePropertyType(property, parentType, ORDER);
const type = determinePropertyType(
property,
parentType,
ORDER,
importedEmberName,
importedInjectName
);
const order = getOrder(ORDER, type);

@@ -206,0 +220,0 @@

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

} = require('../utils/types');
const { findVariable } = require('eslint-utils');

@@ -23,2 +24,3 @@ module.exports = {

getName,
getNodeOrNodeFromVariable,
getPropertyValue,

@@ -234,2 +236,35 @@ getSize,

/**
* Return the passed in node, or if the node is a variable, return the value of this variable.
*
* Example:
* Calling the function on `{ foo: true }` will return the same node.
* Example:
* const x = { foo: true };
* Calling the function on `x` will return the ObjectExpression value.
*
* @param {Node} node
* @param {ScopeManager} scopeManager
* @returns {Node | null}
*/
function getNodeOrNodeFromVariable(node, scopeManager) {
if (node.type === 'Identifier') {
// Find the definition of this variable.
const variable = findVariable(scopeManager.acquire(node) || scopeManager.globalScope, node);
if (
variable &&
variable.defs &&
variable.defs[0] &&
variable.defs[0].node &&
variable.defs[0].node.type === 'VariableDeclarator' &&
variable.defs[0].node.init
) {
return variable.defs[0].node.init;
}
}
// If the node isn't a variable or we can't find the initialized value of it, just return the node itself.
return node;
}
/**
* Check whether a node is inside the left side of an AssignmentExpression.

@@ -236,0 +271,0 @@ *

{
"name": "eslint-plugin-ember",
"version": "10.4.0",
"version": "10.4.1",
"description": "Eslint plugin for Ember.js apps",

@@ -5,0 +5,0 @@ "keywords": [

@@ -158,3 +158,2 @@ # eslint-plugin-ember

| :white_check_mark: | [no-invalid-debug-function-arguments](./docs/rules/no-invalid-debug-function-arguments.md) | disallow usages of Ember's `assert()` / `warn()` / `deprecate()` functions that have the arguments passed in the wrong order. |
| | [no-restricted-service-injections](./docs/rules/no-restricted-service-injections.md) | disallow injecting certain services under certain paths |
| | [require-fetch-import](./docs/rules/require-fetch-import.md) | enforce explicit import for `fetch()` |

@@ -179,2 +178,3 @@

|:---|:--------|:------------|
| | [no-restricted-service-injections](./docs/rules/no-restricted-service-injections.md) | disallow injecting certain services under certain paths |
| :wrench: | [no-unnecessary-service-injection-argument](./docs/rules/no-unnecessary-service-injection-argument.md) | disallow unnecessary argument when injecting services |

@@ -181,0 +181,0 @@ | | [no-unused-services](./docs/rules/no-unused-services.md) | disallow unused service injections |

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc