diff --git a/packages/eslint-plugin-mobx/__tests__/missing-make-observable.js b/packages/eslint-plugin-mobx/__tests__/missing-make-observable.js index 83b5bbaac4..819f929d19 100644 --- a/packages/eslint-plugin-mobx/__tests__/missing-make-observable.js +++ b/packages/eslint-plugin-mobx/__tests__/missing-make-observable.js @@ -248,6 +248,54 @@ constructor() { makeBanana(this); } } )) +const invalid10 = fields.map(field => ({ + code: ` +class C extends Component { + @${field} +} +`, + errors: [ + { messageId: 'missingMakeObservable' }, + ], + output: ` +class C extends Component { +constructor(props) { super(props); makeObservable(this); } + @${field} +} +`, + } +)) + +const invalid11 = fields.map(field => ({ + code: ` +class C extends React.Component<{ foo: string }> { + @${field} +} +`, + errors: [ + { messageId: 'missingMakeObservable' }, + ], + output: ` +class C extends React.Component<{ foo: string }> { +constructor(props: { foo: string }) { super(props); makeObservable(this); } + @${field} +} +`, + } +)) + +const invalid12 = fields.map(field => ({ + code: ` +class C extends Banana { + @${field} +} +`, + errors: [ + { messageId: 'missingMakeObservableSuper' }, + ], + } +)) + tester.run("missing-make-observable", rule, { valid: [ ...valid1, @@ -265,5 +313,8 @@ tester.run("missing-make-observable", rule, { ...invalid7, ...invalid8, ...invalid9, + ...invalid10, + ...invalid11, + ...invalid12, ], }); \ No newline at end of file diff --git a/packages/eslint-plugin-mobx/src/missing-make-observable.js b/packages/eslint-plugin-mobx/src/missing-make-observable.js index 15a4629f49..be6d551af3 100644 --- a/packages/eslint-plugin-mobx/src/missing-make-observable.js +++ b/packages/eslint-plugin-mobx/src/missing-make-observable.js @@ -36,6 +36,9 @@ function create(context) { const constructor = clazz.body.body.find(node => node.kind === 'constructor' && node.value.type === 'FunctionExpression') ?? clazz.body.body.find(node => node.kind === 'constructor'); // MethodDefinition > FunctionExpression > BlockStatement > [] + const isReact = clazz.superClass?.name === 'Component' + || (clazz.superClass?.object?.name === 'React' && clazz.superClass?.property.name === 'Component'); + const unsupportedSuper = !isReact && !!clazz.superClass; const isMakeObservable = node => node.expression?.callee?.name === 'makeObservable' && node.expression?.arguments[0]?.type === 'ThisExpression'; const makeObservable = constructor?.value.body?.body.find(isMakeObservable)?.expression; @@ -50,6 +53,10 @@ function create(context) { } } else { const fix = fixer => { + // The class extends a another unknown class so we can not safely create a super call. + if (unsupportedSuper && !constructor) { + return; + } const fixes = []; let makeObservableExpr = 'makeObservable'; @@ -71,7 +78,15 @@ function create(context) { // constructor() {} const closingBracket = sourceCode.getLastToken(constructor.value.body); fixes.push(fixer.insertTextBefore(closingBracket, `;${makeObservableExpr}(this);`)); - } else { + } else if (isReact) { + // class C extends Component<{ foo: string }> {} + let propsType = ''; + if (clazz.superTypeParameters?.params.length) { + propsType = `: ${sourceCode.getText(clazz.superTypeParameters.params[0])}`; + } + const openingBracket = sourceCode.getFirstToken(clazz.body); + fixes.push(fixer.insertTextAfter(openingBracket, `\nconstructor(props${propsType}) { super(props); ${makeObservableExpr}(this); }`)); + } else if (!unsupportedSuper) { // class C {} const openingBracket = sourceCode.getFirstToken(clazz.body); fixes.push(fixer.insertTextAfter(openingBracket, `\nconstructor() { ${makeObservableExpr}(this); }`)); @@ -82,7 +97,7 @@ function create(context) { context.report({ node: clazz, - messageId: 'missingMakeObservable', + messageId: unsupportedSuper ? 'missingMakeObservableSuper' : 'missingMakeObservable', fix, }) } @@ -101,6 +116,7 @@ module.exports = { }, messages: { missingMakeObservable: "Constructor is missing `makeObservable(this)`.", + missingMakeObservableSuper: "Constructor is missing `makeObservable(this)`. Can not fix because of missing super call.", secondArgMustBeNullish: "`makeObservable`'s second argument must be nullish or not provided when using decorators." }, },