diff --git a/.eslintrc.js b/.eslintrc.js index bf70307de2..af6cec2133 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,7 +24,7 @@ module.exports = { 'prettier', ], env: { - es6: true, + es2020: true, node: true, jest: true, }, diff --git a/lib/rules/no-actions-hash.js b/lib/rules/no-actions-hash.js index b6859b9734..787c4522e0 100644 --- a/lib/rules/no-actions-hash.js +++ b/lib/rules/no-actions-hash.js @@ -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) { diff --git a/lib/rules/no-assignment-of-untracked-properties-used-in-tracking-contexts.js b/lib/rules/no-assignment-of-untracked-properties-used-in-tracking-contexts.js index aaa64e37e7..98c37a79a3 100644 --- a/lib/rules/no-assignment-of-untracked-properties-used-in-tracking-contexts.js +++ b/lib/rules/no-assignment-of-untracked-properties-used-in-tracking-contexts.js @@ -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)) ) diff --git a/lib/rules/no-controllers.js b/lib/rules/no-controllers.js index 12fbff1ef1..e9f84f06bc 100644 --- a/lib/rules/no-controllers.js +++ b/lib/rules/no-controllers.js @@ -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)) ); diff --git a/lib/rules/no-implicit-service-injection-argument.js b/lib/rules/no-implicit-service-injection-argument.js index d7464bbc4c..a625c56504 100644 --- a/lib/rules/no-implicit-service-injection-argument.js +++ b/lib/rules/no-implicit-service-injection-argument.js @@ -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') { @@ -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, }; }, }; diff --git a/lib/rules/no-private-routing-service.js b/lib/rules/no-private-routing-service.js index 50630eb70f..609beea0be 100644 --- a/lib/rules/no-private-routing-service.js +++ b/lib/rules/no-private-routing-service.js @@ -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') { @@ -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 ( diff --git a/lib/rules/no-restricted-service-injections.js b/lib/rules/no-restricted-service-injections.js index a21d667a1d..6bf02f283c 100644 --- a/lib/rules/no-restricted-service-injections.js +++ b/lib/rules/no-restricted-service-injections.js @@ -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') { @@ -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, }; }, }; diff --git a/lib/rules/no-unnecessary-service-injection-argument.js b/lib/rules/no-unnecessary-service-injection-argument.js index c5f2885764..00224fed74 100644 --- a/lib/rules/no-unnecessary-service-injection-argument.js +++ b/lib/rules/no-unnecessary-service-injection-argument.js @@ -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') { @@ -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, }; }, }; diff --git a/lib/rules/no-unused-services.js b/lib/rules/no-unused-services.js index e4b8ae27a5..74dc4f932a 100644 --- a/lib/rules/no-unused-services.js +++ b/lib/rules/no-unused-services.js @@ -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') { @@ -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(); diff --git a/lib/rules/require-tagless-components.js b/lib/rules/require-tagless-components.js index e7a831e924..ef37c9c630 100644 --- a/lib/rules/require-tagless-components.js +++ b/lib/rules/require-tagless-components.js @@ -34,7 +34,7 @@ function isTagNameProperty(node) { } /** - * @param {Property|PropertyDefinition} node + * @param {Property|ClassProperty|PropertyDefinition} node * @return {boolean} */ function isNonEmptyTagNameProperty(node) { @@ -51,7 +51,7 @@ function getNonEmptyTagNameInObjectExpression(node) { /** * @param {ClassBody} node - * @return {PropertyDefinition=} + * @return {ClassProperty|PropertyDefinition=} */ function getNonEmptyTagNameInClassBody(node) { return node.body.find(isNonEmptyTagNameProperty); diff --git a/lib/utils/decorators.js b/lib/utils/decorators.js index c0553ba6e6..be49739ee4 100644 --- a/lib/utils/decorators.js +++ b/lib/utils/decorators.js @@ -7,7 +7,7 @@ module.exports = { findDecorator, findDecoratorByNameCallback, hasDecorator, - isPropertyDefinitionWithDecorator, + isClassPropertyOrPropertyDefinitionWithDecorator, }; /** @@ -62,13 +62,13 @@ function hasDecorator(node, decoratorName) { } /** - * Check whether or not a node is a PropertyDefinition, with at least the given decorator. + * Check whether or not a node is a ClassProperty / PropertyDefinition, with at least the given decorator. * If no decoratorName is provided, will return whether the node has any decorators at all * * @param {Object} node The node to check. * @param {string?} decoratorName The decorator to look for - * @returns {boolean} Whether or not the node is a PropertyDefinition with the given decorator. + * @returns {boolean} Whether or not the node is a ClassProperty / PropertyDefinition with the given decorator. */ -function isPropertyDefinitionWithDecorator(node, decoratorName) { - return types.isPropertyDefinition(node) && hasDecorator(node, decoratorName); +function isClassPropertyOrPropertyDefinitionWithDecorator(node, decoratorName) { + return types.isClassPropertyOrPropertyDefinition(node) && hasDecorator(node, decoratorName); } diff --git a/lib/utils/ember.js b/lib/utils/ember.js index db95384db9..e2edd762ca 100644 --- a/lib/utils/ember.js +++ b/lib/utils/ember.js @@ -119,7 +119,7 @@ function isPropOfType(node, type) { const calleeNode = node.value.callee; return types.isIdentifier(calleeNode) && calleeNode.name === type; } else if ( - (types.isPropertyDefinition(node) || types.isMethodDefinition(node)) && + (types.isClassPropertyOrPropertyDefinition(node) || types.isMethodDefinition(node)) && node.decorators ) { return node.decorators.some((decorator) => { @@ -668,7 +668,7 @@ function isRelation(property) { return relationAttrs.some((relation) => { return ( (property.value && isModule(property.value, relation, 'DS')) || - decoratorUtils.isPropertyDefinitionWithDecorator(property, relation) + decoratorUtils.isClassPropertyOrPropertyDefinitionWithDecorator(property, relation) ); }); } diff --git a/lib/utils/property-order.js b/lib/utils/property-order.js index d95a4a8024..a01c471d4a 100644 --- a/lib/utils/property-order.js +++ b/lib/utils/property-order.js @@ -90,7 +90,7 @@ function determinePropertyType( if (parentType === 'model') { if ( (node.value && ember.isModule(node.value, 'attr', 'DS')) || - decoratorUtils.isPropertyDefinitionWithDecorator(node, 'attr') + decoratorUtils.isClassPropertyOrPropertyDefinitionWithDecorator(node, 'attr') ) { return 'attribute'; } else if (ember.isRelation(node)) { diff --git a/lib/utils/types.js b/lib/utils/types.js index 8f0cc74977..9cfe39f9fb 100644 --- a/lib/utils/types.js +++ b/lib/utils/types.js @@ -9,6 +9,7 @@ module.exports = { isCallExpression, isCallWithFunctionExpression, isClassDeclaration, + isClassPropertyOrPropertyDefinition, isCommaToken, isConciseArrowFunctionWithCallExpression, isConditionalExpression, @@ -29,7 +30,6 @@ module.exports = { isOptionalCallExpression, isOptionalMemberExpression, isProperty, - isPropertyDefinition, isReturnStatement, isSpreadElement, isString, @@ -130,6 +130,18 @@ function isClassDeclaration(node) { return node !== undefined && node.type === 'ClassDeclaration'; } +/** + * Check whether or not a node is a ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8). + * + * @param {Object} node The node to check. + * @returns {boolean} Whether or not the node is a PropertyDefinition. + */ +function isClassPropertyOrPropertyDefinition(node) { + return ( + node !== undefined && (node.type === 'ClassProperty' || node.type === 'PropertyDefinition') + ); +} + function isCommaToken(token) { return token.type === 'Punctuator' && token.value === ','; } @@ -326,16 +338,6 @@ function isProperty(node) { return node !== undefined && node.type === 'Property'; } -/** - * Check whether or not a node is a PropertyDefinition. - * - * @param {Object} node The node to check. - * @returns {boolean} Whether or not the node is a PropertyDefinition. - */ -function isPropertyDefinition(node) { - return node !== undefined && node.type === 'PropertyDefinition'; -} - /** * Check whether or not a node is a ReturnStatement * diff --git a/tests/lib/rules/no-actions-hash.js b/tests/lib/rules/no-actions-hash.js index 6edaa93753..4c83531996 100644 --- a/tests/lib/rules/no-actions-hash.js +++ b/tests/lib/rules/no-actions-hash.js @@ -99,7 +99,12 @@ ruleTester.run('no-actions-hash', rule, { } `, output: null, - errors: [{ type: 'PropertyDefinition', message: ERROR_MESSAGE }], + errors: [ + { + message: ERROR_MESSAGE, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, { code: ` @@ -122,7 +127,12 @@ ruleTester.run('no-actions-hash', rule, { } `, output: null, - errors: [{ type: 'PropertyDefinition', message: ERROR_MESSAGE }], + errors: [ + { + message: ERROR_MESSAGE, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, { code: ` @@ -145,7 +155,12 @@ ruleTester.run('no-actions-hash', rule, { } `, output: null, - errors: [{ type: 'PropertyDefinition', message: ERROR_MESSAGE }], + errors: [ + { + message: ERROR_MESSAGE, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, ], }); diff --git a/tests/lib/rules/no-private-routing-service.js b/tests/lib/rules/no-private-routing-service.js index 35b703bc8c..1e668e207a 100644 --- a/tests/lib/rules/no-private-routing-service.js +++ b/tests/lib/rules/no-private-routing-service.js @@ -88,7 +88,12 @@ ruleTester.run('no-private-routing-service', rule, { { code: `${SERVICE_IMPORT} export default class MyComponent extends Component { @service('-routing') routing; }`, output: null, - errors: [{ message: PRIVATE_ROUTING_SERVICE_ERROR_MESSAGE, type: 'PropertyDefinition' }], + errors: [ + { + message: PRIVATE_ROUTING_SERVICE_ERROR_MESSAGE, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, // _routerMicrolib (`catchRouterMicrolib` option on) diff --git a/tests/lib/rules/no-restricted-service-injections.js b/tests/lib/rules/no-restricted-service-injections.js index d0ccaa6584..a5de958551 100644 --- a/tests/lib/rules/no-restricted-service-injections.js +++ b/tests/lib/rules/no-restricted-service-injections.js @@ -126,7 +126,12 @@ ruleTester.run('no-restricted-service-injections', rule, { code: `${SERVICE_IMPORT} class MyComponent extends Component { @service('myService') randomName }`, output: null, options: [{ paths: ['app/components'], services: ['my-service'] }], - errors: [{ message: DEFAULT_ERROR_MESSAGE, type: 'PropertyDefinition' }], + errors: [ + { + message: DEFAULT_ERROR_MESSAGE, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, { // With decorator with dasherized service name argument: @@ -134,7 +139,12 @@ ruleTester.run('no-restricted-service-injections', rule, { code: `${SERVICE_IMPORT} class MyComponent extends Component { @service('my-service') randomName }`, output: null, options: [{ paths: ['app/components'], services: ['my-service'] }], - errors: [{ message: DEFAULT_ERROR_MESSAGE, type: 'PropertyDefinition' }], + errors: [ + { + message: DEFAULT_ERROR_MESSAGE, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, { // With decorator without service name argument (without parentheses): @@ -142,7 +152,12 @@ ruleTester.run('no-restricted-service-injections', rule, { code: `${SERVICE_IMPORT} class MyComponent extends Component { @service myService }`, output: null, options: [{ paths: ['app/components'], services: ['my-service'] }], - errors: [{ message: DEFAULT_ERROR_MESSAGE, type: 'PropertyDefinition' }], + errors: [ + { + message: DEFAULT_ERROR_MESSAGE, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, { // With decorator without service name argument (with parentheses): @@ -150,7 +165,12 @@ ruleTester.run('no-restricted-service-injections', rule, { code: `${SERVICE_IMPORT} class MyComponent extends Component { @service() myService }`, output: null, options: [{ paths: ['app/components'], services: ['my-service'] }], - errors: [{ message: DEFAULT_ERROR_MESSAGE, type: 'PropertyDefinition' }], + errors: [ + { + message: DEFAULT_ERROR_MESSAGE, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, { // With decorator without service name argument (with parentheses) (with property name as string literal): @@ -158,7 +178,12 @@ ruleTester.run('no-restricted-service-injections', rule, { code: `${SERVICE_IMPORT} class MyComponent extends Component { @service() 'myService' }`, output: null, options: [{ paths: ['app/components'], services: ['my-service'] }], - errors: [{ message: DEFAULT_ERROR_MESSAGE, type: 'PropertyDefinition' }], + errors: [ + { + message: DEFAULT_ERROR_MESSAGE, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, { // With custom error message: diff --git a/tests/lib/rules/no-side-effects.js b/tests/lib/rules/no-side-effects.js index 60d91a2b93..89ddd8432d 100644 --- a/tests/lib/rules/no-side-effects.js +++ b/tests/lib/rules/no-side-effects.js @@ -22,7 +22,7 @@ eslintTester.run('no-side-effects', rule, { 'alias("test.length")', 'computed(function() { this.test; })', 'computed(function() { this.myFunction(); })', - 'computed(function() { class Foo { @someDecorator() someProp } })', // Does not throw with node type (PropertyDefinition) not handled by estraverse. + 'computed(function() { class Foo { @someDecorator() someProp } })', // Does not throw with node type (ClassProperty) not handled by estraverse. // set 'computed(function() { foo.set(this, "testAmount", test.length); return ""; });', diff --git a/tests/lib/rules/no-unused-services.js b/tests/lib/rules/no-unused-services.js index b56cfcb005..6e35988d4c 100644 --- a/tests/lib/rules/no-unused-services.js +++ b/tests/lib/rules/no-unused-services.js @@ -199,7 +199,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT} class MyClass { fooFunc() {${nonUses}} }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -215,7 +215,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT} class MyClass { fooFunc() {${nonUses}} }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -296,7 +296,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT} class MyClass { fooFunc() {${emberObjectUses1}} }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -329,7 +329,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT}${EO_IMPORTS} class MyClass { fooFunc() {${emberObjectUses2}} }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -362,7 +362,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT} class MyClass { @alias('${SERVICE_NAME}') someAlias; @computed('${SERVICE_NAME}.prop') get someComputed() {} }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -395,7 +395,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT}${EO_IMPORTS}${ALIAS_IMPORT} class MyClass { @alias('unrelatedProp', '${SERVICE_NAME}') someAlias; @computed('unrelatedProp.prop') get someComputed() {} }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -427,7 +427,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT}${EO_IMPORTS}${ALIAS_IMPORT} class MyClass { @alias(${SERVICE_NAME}) someAlias; @computed(${SERVICE_NAME}) get someComputed() {} }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -460,7 +460,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT} import {foobar} from '@ember/object/computed'; class MyClass { @foobar('${SERVICE_NAME}') someFoobar; }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -509,7 +509,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT} class MyClass1 { } class MyClass2 { fooFunc() {this.${SERVICE_NAME};} }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -525,7 +525,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT} class MyClass1 { fooFunc() {this.${SERVICE_NAME};} } class MyClass2 { }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -542,7 +542,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT} class MyClass1 { fooFunc1() { class MyClass2 { fooFunc2() {this.${SERVICE_NAME};} } } }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, @@ -558,7 +558,7 @@ ruleTester.run('no-unused-services', rule, { output: `${SERVICE_IMPORT} class MyClass1 { fooFunc1() {this.${SERVICE_NAME};} fooFunc2() { class MyClass2 { } } }`, }, ], - type: 'PropertyDefinition', + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) }, ], }, diff --git a/tests/lib/rules/require-computed-property-dependencies.js b/tests/lib/rules/require-computed-property-dependencies.js index 3e60a14ef2..6711a84cb6 100644 --- a/tests/lib/rules/require-computed-property-dependencies.js +++ b/tests/lib/rules/require-computed-property-dependencies.js @@ -23,7 +23,7 @@ ruleTester.run('require-computed-property-dependencies', rule, { // ES5 getter usage: "import Ember from 'ember'; Ember.computed('name', function() { return this.name; });", "import Ember from 'ember'; Ember.computed('name', function() { return this.get('name'); });", - // Does not throw with node type (PropertyDefinition) not handled by estraverse. + // Does not throw with node type (ClassProperty) not handled by estraverse. "import Ember from 'ember'; Ember.computed('name', function() { class Foo { @someDecorator() someProp } });", // String concatenation in dependent key: "import Ember from 'ember'; Ember.computed('na' + 'me', function() { return this.get('name'); });", diff --git a/tests/lib/rules/require-super-in-lifecycle-hooks.js b/tests/lib/rules/require-super-in-lifecycle-hooks.js index bee26d137d..02161c98f8 100644 --- a/tests/lib/rules/require-super-in-lifecycle-hooks.js +++ b/tests/lib/rules/require-super-in-lifecycle-hooks.js @@ -229,7 +229,7 @@ eslintTester.run('require-super-in-lifecycle-hooks', rule, { "import Component from '@glimmer/component'; class Foo extends Component { init() {} }", "import Component from '@glimmer/component'; class Foo extends Component { didInsertElement() {} }", - // Does not throw with node type (PropertyDefinition) not handled by estraverse. + // Does not throw with node type (ClassProperty) not handled by estraverse. 'Component.extend({init() { class Foo { @someDecorator() someProp }; return this._super(...arguments); } });', ], invalid: [ diff --git a/tests/lib/rules/require-tagless-components.js b/tests/lib/rules/require-tagless-components.js index 720c399470..13d5120326 100644 --- a/tests/lib/rules/require-tagless-components.js +++ b/tests/lib/rules/require-tagless-components.js @@ -162,7 +162,13 @@ ruleTester.run('require-tagless-components', rule, { } `, output: null, - errors: [{ message: ERROR_MESSAGE, line: 4, type: 'PropertyDefinition' }], + errors: [ + { + message: ERROR_MESSAGE, + line: 4, + // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8) + }, + ], }, { code: ` diff --git a/tests/lib/utils/decorators-test.js b/tests/lib/utils/decorators-test.js index 0537790189..5c08c107c0 100644 --- a/tests/lib/utils/decorators-test.js +++ b/tests/lib/utils/decorators-test.js @@ -102,24 +102,32 @@ describe('hasDecorator', () => { } }); -describe('isPropertyDefinitionWithDecorator', () => { +describe('isClassPropertyOrPropertyDefinitionWithDecorator', () => { it('should not find anything with non-decorator', () => { const node = babelESLintParse('const x = 123').body[0]; - expect(decoratorUtils.isPropertyDefinitionWithDecorator(node, 'random')).toBe(false); + expect(decoratorUtils.isClassPropertyOrPropertyDefinitionWithDecorator(node, 'random')).toBe( + false + ); }); it('should not find anything with wrong decorator name', () => { const node = babelESLintParse('class Test { @tracked x }').body[0].body.body[0]; - expect(decoratorUtils.isPropertyDefinitionWithDecorator(node, 'random')).toBe(false); + expect(decoratorUtils.isClassPropertyOrPropertyDefinitionWithDecorator(node, 'random')).toBe( + false + ); }); it('should find something with Identifier decorator', () => { const node = babelESLintParse('class Test { @tracked x }').body[0].body.body[0]; - expect(decoratorUtils.isPropertyDefinitionWithDecorator(node, 'tracked')).toBe(true); + expect(decoratorUtils.isClassPropertyOrPropertyDefinitionWithDecorator(node, 'tracked')).toBe( + true + ); }); it('should find something with CallExpression decorator', () => { const node = babelESLintParse('class Test { @tracked x }').body[0].body.body[0]; - expect(decoratorUtils.isPropertyDefinitionWithDecorator(node, 'tracked')).toBe(true); + expect(decoratorUtils.isClassPropertyOrPropertyDefinitionWithDecorator(node, 'tracked')).toBe( + true + ); }); }); diff --git a/tests/lib/utils/scope-references-this-test.js b/tests/lib/utils/scope-references-this-test.js index a65cabd81a..fd1fc98b71 100644 --- a/tests/lib/utils/scope-references-this-test.js +++ b/tests/lib/utils/scope-references-this-test.js @@ -11,7 +11,7 @@ describe('scopeReferencesThis', function () { it('recognizes simple cases`', function () { expect(scopeReferencesThis(parse('this'))).toBeTruthy(); // `this` uses `this` expect(scopeReferencesThis(parse('"this"'))).toBeFalsy(); // the string "this" does not use this - expect(scopeReferencesThis(parse('class Foo { @someDecorator() someProp }'))).toBeFalsy(); // Does not throw with node type (PropertyDefinition) not handled by estraverse. + expect(scopeReferencesThis(parse('class Foo { @someDecorator() someProp }'))).toBeFalsy(); // Does not throw with node type (ClassProperty) not handled by estraverse. }); it('can find nested `this`', function () {