Skip to content

Commit

Permalink
es2020
Browse files Browse the repository at this point in the history
  • Loading branch information
bmish committed Jul 20, 2022
1 parent 4adbf57 commit c7f25b4
Show file tree
Hide file tree
Showing 24 changed files with 273 additions and 187 deletions.
2 changes: 1 addition & 1 deletion .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
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, 'PropertyDefinition'));
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.isPropertyDefinition(node) &&
types.isClassPropertyOrPropertyDefinition(node) &&
decoratorUtils.hasDecorator(node, trackedImportName) &&
(types.isIdentifier(node.key) || types.isStringLiteral(node.key))
)
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-controllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function classDeclarationHasProperty(classDeclaration, propertyName) {
assert(types.isClassDeclaration(classDeclaration));
return classDeclaration.body.body.some(
(item) =>
types.isPropertyDefinition(item) &&
types.isClassPropertyOrPropertyDefinition(item) &&
((types.isIdentifier(item.key) && item.key.name === propertyName) ||
(types.isStringLiteral(item.key) && item.key.value === propertyName))
);
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 = {
});
}
},

PropertyDefinition(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,
};
},
};
48 changes: 26 additions & 22 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,28 +105,8 @@ module.exports = {
}
},

PropertyDefinition(node) {
if (
!node.decorators ||
!decoratorUtils.isPropertyDefinitionWithDecorator(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
PropertyDefinition(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,
};
},
};
52 changes: 28 additions & 24 deletions lib/rules/no-unnecessary-service-injection-argument.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,32 @@ module.exports = {
let importedInjectName;
let importedEmberName;

// Handle both ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8).
function visitClassPropertyOrPropertyDefinition(node) {
if (
!emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName) ||
node.decorators.length !== 1 ||
!types.isCallExpression(node.decorators[0].expression) ||
node.decorators[0].expression.arguments.length !== 1 ||
!types.isStringLiteral(node.decorators[0].expression.arguments[0])
) {
return;
}

const keyName = node.key.name || node.key.value;
const firstArg = node.decorators[0].expression.arguments[0];
const firstArgValue = firstArg.value;
if (keyName === firstArgValue) {
context.report({
node: firstArg,
message: ERROR_MESSAGE,
fix(fixer) {
return fixer.remove(firstArg);
},
});
}
}

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

PropertyDefinition(node) {
if (
!emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName) ||
node.decorators.length !== 1 ||
!types.isCallExpression(node.decorators[0].expression) ||
node.decorators[0].expression.arguments.length !== 1 ||
!types.isStringLiteral(node.decorators[0].expression.arguments[0])
) {
return;
}

const keyName = node.key.name || node.key.value;
const firstArg = node.decorators[0].expression.arguments[0];
const firstArgValue = firstArg.value;
if (keyName === firstArgValue) {
context.report({
node: firstArg,
message: ERROR_MESSAGE,
fix(fixer) {
return fixer.remove(firstArg);
},
});
}
},
ClassProperty: visitClassPropertyOrPropertyDefinition,
PropertyDefinition: visitClassPropertyOrPropertyDefinition,
};
},
};
47 changes: 27 additions & 20 deletions lib/rules/no-unused-services.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,30 @@ module.exports = {
}
}

// Handle both ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8).
function visitClassPropertyOrPropertyDefinition(node) {
// Handles:
// @service(...) foo;
// If Ember and Ember.inject weren't imported, skip out early
if (!importedEmberName && !importedInjectName) {
return;
}

const currentClass = classStack.peek();
if (
currentClass &&
emberUtils.isInjectedServiceProp(node, importedEmberName, importedInjectName)
) {
if (node.key.type === 'Identifier') {
const name = node.key.name;
currentClass.services[name] = node;
} else if (types.isStringLiteral(node.key)) {
const name = node.key.value;
currentClass.services[name] = node;
}
}
}

return {
ImportDeclaration(node) {
if (node.source.value === '@ember/object') {
Expand Down Expand Up @@ -332,27 +356,10 @@ module.exports = {
}
}
},
// @service(...) foo;
PropertyDefinition(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, importedEmberName, importedInjectName)
) {
if (node.key.type === 'Identifier') {
const name = node.key.name;
currentClass.services[name] = node;
} else if (types.isStringLiteral(node.key)) {
const name = node.key.value;
currentClass.services[name] = node;
}
}
},
ClassProperty: visitClassPropertyOrPropertyDefinition,
PropertyDefinition: visitClassPropertyOrPropertyDefinition,

// this.foo...
MemberExpression(node) {
const currentClass = classStack.peek();
Expand Down
Loading

0 comments on commit c7f25b4

Please sign in to comment.