diff --git a/lib/rules/decorator-position.js b/lib/rules/decorator-position.js index 0f6204d7..ef95fe61 100644 --- a/lib/rules/decorator-position.js +++ b/lib/rules/decorator-position.js @@ -133,6 +133,12 @@ const INTENT = { DIFFERENT_LINES: 'different-line', }; +const EXPRESSION_TYPES = { + CALL_EXPRESSION: 'CallExpression', + IDENTIFIER: 'Identifier', + MEMBER_EXPRESSION: 'MemberExpression', +}; + const PREFER_INLINE = 'prefer-inline'; const ABOVE = 'above'; @@ -467,13 +473,16 @@ function lengthAsInline(context, node) { ); } -function isMultiline(context, decorator, node) { +function isMultilineExpression(context, decorator, node) { const code = context.getSourceCode(); const dec = code.getText(decorator); const all = code.getText(node); const withoutDecorator = all.replace(dec, ''); - return withoutDecorator.split('\n').length > 1; + const isValueCallExpression = + node && node.value && node.value.type === EXPRESSION_TYPES.CALL_EXPRESSION; + + return withoutDecorator.split('\n').length > 1 && isValueCallExpression; } function decoratorInfo(context, node, decoratorConfig, options) { @@ -489,7 +498,7 @@ function decoratorInfo(context, node, decoratorConfig, options) { return {}; } - const multiline = isMultiline(context, decorator, node); + const multiline = isMultilineExpression(context, decorator, node); const inlineLength = lengthAsInline(context, node); const ifInlineWouldViolatePrettier = inlineLength > printWidth; @@ -515,7 +524,7 @@ function decoratorInfo(context, node, decoratorConfig, options) { } if ( - decoratorOptions === INTENT.SAME_LINE && + decoratorOptions.intent === INTENT.SAME_LINE && positioning.onDifferentLines && ifInlineWouldViolatePrettier ) { @@ -543,11 +552,11 @@ function decoratorInfo(context, node, decoratorConfig, options) { function nameOfExpression(expression) { const { type } = expression; switch (type) { - case 'CallExpression': + case EXPRESSION_TYPES.CALL_EXPRESSION: return nameOfExpression(expression.callee); - case 'Identifier': + case EXPRESSION_TYPES.IDENTIFIER: return expression.name; - case 'MemberExpression': + case EXPRESSION_TYPES.MEMBER_EXPRESSION: return `${nameOfExpression(expression.object)}.${nameOfExpression(expression.property)}`; default: throw new Error(`Decorator of type ${type} not yet handled`); @@ -562,7 +571,7 @@ function arityOfDecorator(decorator) { const type = decorator.expression.type; switch (type) { - case 'CallExpression': + case EXPRESSION_TYPES.CALL_EXPRESSION: return decorator.expression.arguments.length; default: return undefined; diff --git a/tests/lib/rules/decorator-position-js.js b/tests/lib/rules/decorator-position-js.js index 8d086f03..1e2315f6 100644 --- a/tests/lib/rules/decorator-position-js.js +++ b/tests/lib/rules/decorator-position-js.js @@ -196,6 +196,32 @@ describe(`JavaScript (using ${using})`, () => { // print width is one less than the decorator would be on one line options: [{ printWidth: 31 }], }, + { + code: stripIndent` + class Foo { + @foo one() {} + + @foo two() { + return 2; + } + } + `, + options: [{ overrides: { 'prefer-inline': ['@foo'] } }], + }, + { + code: stripIndent` + class Foo { + @foo + one() {} + + @foo + two() { + return 2; + } + } + `, + options: [{ methods: 'above', properties: 'prefer-inline' }], + }, ], invalid: [ { @@ -362,6 +388,31 @@ describe(`JavaScript (using ${using})`, () => { } `, }, + { + code: stripIndent` + class Foo { + @foo + one() {} + + @foo two() { + return 2; + } + } + `, + options: [{ methods: 'above', properties: 'prefer-inline' }], + errors: [{ message: 'Expected @foo to be on the line above.' }], + output: stripIndent` + class Foo { + @foo + one() {} + + @foo + two() { + return 2; + } + } + `, + }, ], }); }); diff --git a/tests/lib/rules/decorator-position-ts.js b/tests/lib/rules/decorator-position-ts.js index b555f854..0f917295 100644 --- a/tests/lib/rules/decorator-position-ts.js +++ b/tests/lib/rules/decorator-position-ts.js @@ -41,6 +41,13 @@ describe('TypeScript (using @typescript-eslint/parser)', () => { .join(" "); } `, + stripIndent` + export class MyComponent { + @State classes = ["toggle", this.checkedClass(), this.disabledClass()] + .filter(Boolean) + .join(" "); + } + `, { code: stripIndent` export default class LocaleSwitcher extends Component {