Skip to content

Commit

Permalink
Update to ESLint v8
Browse files Browse the repository at this point in the history
  • Loading branch information
bmish committed Jul 20, 2022
1 parent e56d55f commit 7f9ace4
Show file tree
Hide file tree
Showing 41 changed files with 608 additions and 695 deletions.
7 changes: 3 additions & 4 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ module.exports = {
'prettier',
],
env: {
es6: true,
es2020: true,
node: true,
jest: true,
},
Expand Down Expand Up @@ -111,20 +111,19 @@ module.exports = {

// Optional jest rules:
'jest/consistent-test-it': 'error',
'jest/lowercase-name': 'error',
'jest/no-duplicate-hooks': 'error',
'jest/no-expect-resolves': 'error',
'jest/no-hooks': 'error',
'jest/no-if': 'error',
'jest/no-large-snapshots': 'error',
'jest/no-test-return-statement': 'error',
'jest/prefer-called-with': 'error',
'jest/prefer-hooks-on-top': 'error',
'jest/prefer-lowercase-title': 'error',
'jest/prefer-spy-on': 'error',
'jest/prefer-strict-equal': 'error',
'jest/prefer-todo': 'error',
'jest/require-top-level-describe': 'error',
'jest/require-to-throw-message': 'error',
'jest/require-top-level-describe': 'error',
'jest/valid-title': 'error',

// Optional import rules:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ jobs:
- run: yarn update && git diff --exit-code

- run: yarn test:coverage --runInBand

- run: yarn add --dev eslint@7 && yarn test --runInBand
1 change: 1 addition & 0 deletions lib/rules/new-module-imports.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const MAPPING = require('ember-rfc176-data');
const { buildMessage, getFullNames, isDestructuring } = require('../utils/new-module');
const { getSourceModuleNameForIdentifier } = require('../utils/import');

// eslint-disable-next-line unicorn/prefer-object-from-entries
const GLOBALS = MAPPING.reduce((memo, exportDefinition) => {
if (exportDefinition.deprecated) {
return memo;
Expand Down
5 changes: 4 additions & 1 deletion lib/rules/no-actions-hash.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ module.exports = {
return {
ClassDeclaration(node) {
if (inClassWhichCanContainActions(context, node)) {
reportActionsProp(utils.findNodes(node.body.body, 'ClassProperty'));
reportActionsProp([
...utils.findNodes(node.body.body, 'ClassProperty'),
...utils.findNodes(node.body.body, 'PropertyDefinition'),
]);
}
},
CallExpression(node) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function findTrackedProperties(nodeClassDeclaration, trackedImportName) {
nodeClassDeclaration.body.body
.filter(
(node) =>
types.isClassProperty(node) &&
types.isClassPropertyOrPropertyDefinition(node) &&
decoratorUtils.hasDecorator(node, trackedImportName) &&
(types.isIdentifier(node.key) || types.isStringLiteral(node.key))
)
Expand Down
40 changes: 17 additions & 23 deletions lib/rules/no-controllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,32 +49,26 @@ module.exports = {

function classDeclarationHasProperty(classDeclaration, propertyName) {
assert(types.isClassDeclaration(classDeclaration));
return (
classDeclaration.body.body.length > 0 &&
classDeclaration.body.body.some(
(item) =>
types.isClassProperty(item) &&
((types.isIdentifier(item.key) && item.key.name === propertyName) ||
(types.isStringLiteral(item.key) && item.key.value === propertyName))
)
return classDeclaration.body.body.some(
(item) =>
types.isClassPropertyOrPropertyDefinition(item) &&
((types.isIdentifier(item.key) && item.key.name === propertyName) ||
(types.isStringLiteral(item.key) && item.key.value === propertyName))
);
}

function callExpressionClassHasProperty(callExpression, propertyName, scopeManager) {
assert(types.isCallExpression(callExpression));
return (
callExpression.arguments.length > 0 &&
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) ||
(types.isStringLiteral(prop.key) && prop.key.value === propertyName)
)
);
})
);
return 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) ||
(types.isStringLiteral(prop.key) && prop.key.value === propertyName)
)
);
});
}
8 changes: 3 additions & 5 deletions lib/rules/no-duplicate-dependent-keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,9 @@ module.exports = {
return null;
}

return duplicateNodes
.map((duplicateNode) =>
fixerUtils.removeCommaSeparatedNode(duplicateNode, sourceCode, fixer)
)
.flat();
return duplicateNodes.flatMap((duplicateNode) =>
fixerUtils.removeCommaSeparatedNode(duplicateNode, sourceCode, fixer)
);
},
});
}
Expand Down
85 changes: 44 additions & 41 deletions lib/rules/no-implicit-service-injection-argument.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,48 @@ module.exports = {
let importedInjectName;
let importedEmberName;

// Handle both ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8).
function visitClassPropertyOrPropertyDefinition(node) {
// Handle native classes.

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

if (
types.isCallExpression(node.decorators[0].expression) &&
node.decorators[0].expression.arguments.length > 0
) {
// Already has the service name argument.
return;
}

context.report({
node: node.decorators[0].expression,
message: ERROR_MESSAGE,
fix(fixer) {
const sourceCode = context.getSourceCode();

// Ideally, we want to match the service's filename, and kebab-case filenames are most common.
const serviceName = emberUtils.convertServiceNameToKebabCase(
node.key.name || node.key.value
);

return node.decorators[0].expression.type === 'CallExpression'
? // Add after parenthesis.
fixer.insertTextAfter(
sourceCode.getTokenAfter(node.decorators[0].expression.callee),
`'${serviceName}'`
)
: // No parenthesis yet so we need to add them.
fixer.insertTextAfter(node.decorators[0].expression, `('${serviceName}')`);
},
});
}

return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
Expand Down Expand Up @@ -71,47 +113,8 @@ module.exports = {
});
}
},

ClassProperty(node) {
// Native classes.

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

if (
types.isCallExpression(node.decorators[0].expression) &&
node.decorators[0].expression.arguments.length > 0
) {
// Already has the service name argument.
return;
}

context.report({
node: node.decorators[0].expression,
message: ERROR_MESSAGE,
fix(fixer) {
const sourceCode = context.getSourceCode();

// Ideally, we want to match the service's filename, and kebab-case filenames are most common.
const serviceName = emberUtils.convertServiceNameToKebabCase(
node.key.name || node.key.value
);

return node.decorators[0].expression.type === 'CallExpression'
? // Add after parenthesis.
fixer.insertTextAfter(
sourceCode.getTokenAfter(node.decorators[0].expression.callee),
`'${serviceName}'`
)
: // No parenthesis yet so we need to add them.
fixer.insertTextAfter(node.decorators[0].expression, `('${serviceName}')`);
},
});
},
ClassProperty: visitClassPropertyOrPropertyDefinition,
PropertyDefinition: visitClassPropertyOrPropertyDefinition,
};
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ module.exports = {
})
);

for (const functionRule of [...inactiveFunctionRules]) {
for (const functionRule of inactiveFunctionRules) {
if (functionRule.importPath === importPath && namedImports.has(functionRule.importName)) {
inactiveFunctionRules.delete(functionRule);
activeFunctionRules.add(functionRule);
Expand All @@ -74,7 +74,7 @@ module.exports = {
}
},
CallExpression(node) {
for (const functionRule of [...activeFunctionRules]) {
for (const functionRule of activeFunctionRules) {
checkFunctionRule(functionRule, node);
}

Expand Down
45 changes: 26 additions & 19 deletions lib/rules/no-private-routing-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,30 @@ module.exports = {
let importedInjectName;
let importedEmberName;

// Handle both ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8).
function visitClassPropertyOrPropertyDefinition(node) {
if (
!node.decorators ||
!decoratorUtils.isClassPropertyOrPropertyDefinitionWithDecorator(node, 'service')
) {
return;
}

const hasRoutingServiceDecorator = node.decorators.some((decorator) => {
const expression = decorator.expression;
return (
expression &&
expression.arguments &&
expression.arguments.length > 0 &&
expression.arguments[0].value === ROUTING_SERVICE_NAME
);
});

if (hasRoutingServiceDecorator) {
context.report({ node, message: PRIVATE_ROUTING_SERVICE_ERROR_MESSAGE });
}
}

return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
Expand All @@ -81,25 +105,8 @@ module.exports = {
}
},

ClassProperty(node) {
if (!node.decorators || !decoratorUtils.isClassPropertyWithDecorator(node, 'service')) {
return;
}

const hasRoutingServiceDecorator = node.decorators.some((decorator) => {
const expression = decorator.expression;
return (
expression &&
expression.arguments &&
expression.arguments.length > 0 &&
expression.arguments[0].value === ROUTING_SERVICE_NAME
);
});

if (hasRoutingServiceDecorator) {
context.report({ node, message: PRIVATE_ROUTING_SERVICE_ERROR_MESSAGE });
}
},
ClassProperty: visitClassPropertyOrPropertyDefinition,
PropertyDefinition: visitClassPropertyOrPropertyDefinition,

Literal(node) {
if (
Expand Down
52 changes: 28 additions & 24 deletions lib/rules/no-restricted-service-injections.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,32 @@ module.exports = {
let importedInjectName;
let importedEmberName;

// Handle both ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8).
// Handles:
// * @service myService
// * @service() myService
// * @service('myService') propertyName
function visitClassPropertyOrPropertyDefinition(node) {
if (!emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName)) {
return;
}

// Find the service decorator.
const serviceDecorator = decoratorUtils.findDecorator(node, 'service');

// Get the service name either from the string argument or from the property name.
const serviceName =
serviceDecorator.expression.type === 'CallExpression' &&
serviceDecorator.expression.arguments &&
serviceDecorator.expression.arguments.length === 1 &&
serviceDecorator.expression.arguments[0].type === 'Literal' &&
typeof serviceDecorator.expression.arguments[0].value === 'string'
? serviceDecorator.expression.arguments[0].value
: node.key.name || node.key.value;

checkForViolationAndReport(node, serviceName);
}

return {
ImportDeclaration(node) {
if (node.source.value === 'ember') {
Expand Down Expand Up @@ -127,30 +153,8 @@ module.exports = {
}
},

// Handles:
// * @service myService
// * @service() myService
// * @service('myService') propertyName
ClassProperty(node) {
if (!emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName)) {
return;
}

// Find the service decorator.
const serviceDecorator = decoratorUtils.findDecorator(node, 'service');

// Get the service name either from the string argument or from the property name.
const serviceName =
serviceDecorator.expression.type === 'CallExpression' &&
serviceDecorator.expression.arguments &&
serviceDecorator.expression.arguments.length === 1 &&
serviceDecorator.expression.arguments[0].type === 'Literal' &&
typeof serviceDecorator.expression.arguments[0].value === 'string'
? serviceDecorator.expression.arguments[0].value
: node.key.name || node.key.value;

checkForViolationAndReport(node, serviceName);
},
ClassProperty: visitClassPropertyOrPropertyDefinition,
PropertyDefinition: visitClassPropertyOrPropertyDefinition,
};
},
};
Loading

0 comments on commit 7f9ace4

Please sign in to comment.