diff --git a/packages/eslint-plugin-sui/src/rules/decorator-deprecated-remark-method.js b/packages/eslint-plugin-sui/src/rules/decorator-deprecated-remark-method.js index 1cbe14101..214af8a68 100644 --- a/packages/eslint-plugin-sui/src/rules/decorator-deprecated-remark-method.js +++ b/packages/eslint-plugin-sui/src/rules/decorator-deprecated-remark-method.js @@ -4,71 +4,12 @@ 'use strict' const dedent = require('string-dedent') +const {getDecoratorsByNode, getElementMessageName, getElementName, remarkElement} = require('../utils/decorators.js') // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ -function getElementName(node, {isAClass, isAMethod, isArrowFunction}) { - if (isAClass) { - const className = node.id?.name ?? 'UnknownClass' - return `class ${className}` - } - - if (isArrowFunction) { - const methodNode = node.parent - const classNode = methodNode?.parent?.parent - const className = classNode.id?.name ?? 'UnknownClass' - const methodName = methodNode.key?.name ?? 'UnknownMethod' - - return `method ${className}.${methodName}` - } - - if (isAMethod) { - const classNode = node.parent?.parent - const className = classNode.id?.name ?? 'UnknownClass' - const methodName = node.key?.name ?? 'UnknownMethod' - - return `method ${className}.${methodName}` - } - - return 'unknown' -} - -function getDecoratorsNode(node, {isAClass, isAMethod, isArrowFunction}) { - if (isAClass) { - return node.decorators - } - - if (isArrowFunction) { - const methodNode = node.parent - return methodNode.decorators ?? [] - } - - if (isAMethod) { - return node.decorators ?? [] - } - - return [] -} - -function remarkElement(node, {isAClass, isAMethod, isArrowFunction}) { - if (isAClass) { - return node.id - } - - if (isArrowFunction) { - const methodNode = node.parent - return methodNode.key - } - - if (isAMethod) { - return node.key - } - - return node -} - /** @type {import('eslint').Rule.RuleModule} */ module.exports = { meta: { @@ -93,7 +34,7 @@ module.exports = { const isAMethod = node.type === 'MethodDefinition' const nodeName = getElementName(node, {isAClass, isAMethod, isArrowFunction}) - const decorators = getDecoratorsNode(node, {isAClass, isAMethod, isArrowFunction}) + const decorators = getDecoratorsByNode(node, {isAClass, isAMethod, isArrowFunction}) const hasDecorators = decorators?.length > 0 // Get the @Deprecated() decorator from node decorators @@ -101,8 +42,8 @@ module.exports = { hasDecorators && decorators?.find(decorator => decorator?.expression?.callee?.name === 'Deprecated') if (!deprecatedDecoratorNode) return - console.log(nodeName, deprecatedDecoratorNode) + const elementMessageName = getElementMessageName(nodeName, {isAClass, isAMethod, isArrowFunction}) const nodeToRemark = remarkElement(node, {isAClass, isAMethod, isArrowFunction}) // RULE: Mark method with a warning @@ -110,7 +51,7 @@ module.exports = { node: nodeToRemark, messageId: 'remarkWarningMessage', data: { - methodName: nodeName + methodName: elementMessageName } }) } diff --git a/packages/eslint-plugin-sui/src/rules/decorator-deprecated.js b/packages/eslint-plugin-sui/src/rules/decorator-deprecated.js index 11465ddd6..7d9f4b019 100644 --- a/packages/eslint-plugin-sui/src/rules/decorator-deprecated.js +++ b/packages/eslint-plugin-sui/src/rules/decorator-deprecated.js @@ -4,6 +4,7 @@ 'use strict' const dedent = require('string-dedent') +const {getDecoratorsByNode, getElementName, getElementMessageName} = require('../utils/decorators') // ------------------------------------------------------------------------------ // Rule Definition @@ -33,83 +34,86 @@ module.exports = { } }, create: function (context) { - // TODO: Check using decorator in a Class. - return { - MethodDefinition(node) { - // Method - const method = node - const methodName = method.key?.name + function ruleRunner(node) { + const isAClass = node.type === 'ClassDeclaration' + const isArrowFunction = node.type === 'ArrowFunctionExpression' + const isAMethod = node.type === 'MethodDefinition' - // Method decorators - const methodDecorators = method.decorators - const hasDecorators = methodDecorators?.length > 0 + const nodeName = getElementName(node, {isAClass, isAMethod, isArrowFunction}) + const decorators = getDecoratorsByNode(node, {isAClass, isAMethod, isArrowFunction}) + const hasDecorators = decorators?.length > 0 - if (!hasDecorators) return + // Get the @Deprecated() decorator from node decorators + const deprecatedDecoratorNode = + hasDecorators && decorators?.find(decorator => decorator?.expression?.callee?.name === 'Deprecated') - // Get the @Deprecated() decorator from method - const deprecatedDecoratorNode = - hasDecorators && methodDecorators?.find(decorator => decorator?.expression?.callee?.name === 'Deprecated') + if (!deprecatedDecoratorNode) return - if (!deprecatedDecoratorNode) return + const deprecatedDecoratorArguments = deprecatedDecoratorNode.expression?.arguments + // The decorator must have 1 argument and it should be an object + const hasArgument = deprecatedDecoratorArguments.length === 1 + const argumentDecorator = hasArgument && deprecatedDecoratorArguments[0] + const isObjectExpression = hasArgument && argumentDecorator.type === 'ObjectExpression' + const argumentsAreInvalid = !hasArgument || !isObjectExpression - const methodArguments = deprecatedDecoratorNode?.expression?.arguments - const hasArgument = methodArguments.length === 1 - const argumentDecorator = hasArgument && methodArguments[0] - const isObjectExpression = hasArgument && argumentDecorator.type === 'ObjectExpression' - const argumentsAreInvalid = !hasArgument || !isObjectExpression + // Get decorator arguments: key and message + const keyProperty = !argumentsAreInvalid && argumentDecorator.properties?.find(prop => prop?.key?.name === 'key') + const messageProperty = + !argumentsAreInvalid && argumentDecorator.properties?.find(prop => prop?.key?.name === 'message') - // Get decorator arguments: key and message - const keyProperty = - !argumentsAreInvalid && argumentDecorator.properties?.find(prop => prop?.key?.name === 'key') - const messageProperty = - !argumentsAreInvalid && argumentDecorator.properties?.find(prop => prop?.key?.name === 'message') + const elementMessageName = getElementMessageName(nodeName, {isAClass, isAMethod, isArrowFunction}) - // RULE: Decorator must have 1 argument as an object with Key and Message properties - if (argumentsAreInvalid || (!keyProperty && !messageProperty)) { - context.report({ - node: deprecatedDecoratorNode, - messageId: 'notFoundDecoratorArgumentError', - *fix(fixer) { - yield fixer.insertTextBefore( - deprecatedDecoratorNode, - `\n @Deprecated({key: '${methodName}', message: 'The ${methodName} function is deprecated.'})` - ) - yield fixer.remove(deprecatedDecoratorNode) - } - }) - return - } + // RULE: Decorator must have 1 argument as an object with Key and Message properties + if (argumentsAreInvalid || (!keyProperty && !messageProperty)) { + context.report({ + node: deprecatedDecoratorNode, + messageId: 'notFoundDecoratorArgumentError', + *fix(fixer) { + yield fixer.insertTextBefore( + deprecatedDecoratorNode, + `\n @Deprecated({key: '${nodeName}', message: 'The ${elementMessageName} is deprecated.'})` + ) + yield fixer.remove(deprecatedDecoratorNode) + } + }) + return + } - // RULE: Decorator must have a key property and generates it if it doesn't exist - if (!keyProperty && messageProperty) { - context.report({ - node: deprecatedDecoratorNode, - messageId: 'notFoundKeyDecoratorArgumentError', - *fix(fixer) { - yield fixer.insertTextBefore( - deprecatedDecoratorNode, - `\n @Deprecated({key: '${methodName}', message: '${messageProperty.value.value}'})` - ) - yield fixer.remove(deprecatedDecoratorNode) - } - }) - } + // RULE: Decorator must have a key property and generates it if it doesn't exist + if (!keyProperty && messageProperty) { + context.report({ + node: deprecatedDecoratorNode, + messageId: 'notFoundKeyDecoratorArgumentError', + *fix(fixer) { + yield fixer.insertTextBefore( + deprecatedDecoratorNode, + `\n @Deprecated({key: '${nodeName}', message: '${messageProperty.value.value}'})` + ) + yield fixer.remove(deprecatedDecoratorNode) + } + }) + } - // RULE: Decorator must have a message property and generates it if it doesn't exist - if (keyProperty && !messageProperty) { - context.report({ - node: deprecatedDecoratorNode, - messageId: 'notFoundMessageDecoratorArgumentError', - *fix(fixer) { - yield fixer.insertTextBefore( - deprecatedDecoratorNode, - `\n @Deprecated({key: '${keyProperty.value.value}', message: 'The ${methodName} function is deprecated.'})` - ) - yield fixer.remove(deprecatedDecoratorNode) - } - }) - } + // RULE: Decorator must have a message property and generates it if it doesn't exist + if (keyProperty && !messageProperty) { + context.report({ + node: deprecatedDecoratorNode, + messageId: 'notFoundMessageDecoratorArgumentError', + *fix(fixer) { + yield fixer.insertTextBefore( + deprecatedDecoratorNode, + `\n @Deprecated({key: '${keyProperty.value.value}', message: 'The ${elementMessageName} function is deprecated.'})` + ) + yield fixer.remove(deprecatedDecoratorNode) + } + }) } } + + return { + ClassDeclaration: ruleRunner, + MethodDefinition: ruleRunner, + ArrowFunctionExpression: ruleRunner + } } } diff --git a/packages/eslint-plugin-sui/src/utils/decorators.js b/packages/eslint-plugin-sui/src/utils/decorators.js new file mode 100644 index 000000000..2ad0c83c6 --- /dev/null +++ b/packages/eslint-plugin-sui/src/utils/decorators.js @@ -0,0 +1,76 @@ +function getDecoratorsByNode(node, {isAClass, isAMethod, isArrowFunction}) { + if (isAClass) { + return node.decorators + } + + if (isArrowFunction) { + const methodNode = node.parent + return methodNode.decorators ?? [] + } + + if (isAMethod) { + return node.decorators ?? [] + } + + return [] +} + +function getElementName(node, {isAClass, isAMethod, isArrowFunction}) { + if (isAClass) { + const className = node.id?.name ?? 'UnknownClass' + return `${className}` + } + + if (isArrowFunction) { + const methodNode = node.parent + const classNode = methodNode?.parent?.parent + const className = classNode.id?.name ?? 'UnknownClass' + const methodName = methodNode.key?.name ?? 'UnknownMethod' + + return `${className}.${methodName}` + } + + if (isAMethod) { + const classNode = node.parent?.parent + const className = classNode.id?.name ?? 'UnknownClass' + const methodName = node.key?.name ?? 'UnknownMethod' + + return `${className}.${methodName}` + } + + return 'unknown' +} + +function getElementMessageName(elementName, {isAClass, isAMethod, isArrowFunction}) { + if (isAClass) { + return `class ${elementName}` + } + + if (isAMethod || isArrowFunction) { + return `method ${elementName}` + } + + return 'Unknown' +} + +function remarkElement(node, {isAClass, isAMethod, isArrowFunction}) { + if (isAClass) { + return node.id + } + + if (isArrowFunction) { + const methodNode = node.parent + return methodNode.key + } + + if (isAMethod) { + return node.key + } + + return node +} + +module.exports.getDecoratorsByNode = getDecoratorsByNode +module.exports.getElementMessageName = getElementMessageName +module.exports.getElementName = getElementName +module.exports.remarkElement = remarkElement