-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
eslint: missing-observer, no-anonymous-observer (#3219)
- Loading branch information
Showing
25 changed files
with
2,869 additions
and
2,379 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"eslint-plugin-mobx": patch | ||
--- | ||
|
||
Add [`mobx/missing-observer`](https://github.com/mobxjs/mobx/tree/main/packages/eslint-plugin-mobx#mobxmissing-observer), | ||
[`mobx/no-anonymous-observer`](https://github.com/mobxjs/mobx/tree/main/packages/eslint-plugin-mobx#mobxno-anonymous-observer) rules, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
packages/eslint-plugin-mobx/__tests__/TODO-missing-observer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { RuleTester } from "eslint"; | ||
|
||
import rule from "../src/missing-observer.js"; | ||
|
||
const tester = new RuleTester({ | ||
parser: require.resolve('@typescript-eslint/parser'), | ||
parserOptions: {} | ||
}); | ||
|
||
tester.run("missing-observer", rule, { | ||
valid: [ | ||
{ code: `` }, | ||
], | ||
invalid: [], | ||
}); |
15 changes: 15 additions & 0 deletions
15
packages/eslint-plugin-mobx/__tests__/TODO-no-anonymous-observer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { RuleTester } from "eslint"; | ||
|
||
import rule from "../src/no-anonymous-observer.js"; | ||
|
||
const tester = new RuleTester({ | ||
parser: require.resolve('@typescript-eslint/parser'), | ||
parserOptions: {} | ||
}); | ||
|
||
tester.run("no-anonymous-observer", rule, { | ||
valid: [ | ||
{ code: `` }, | ||
], | ||
invalid: [], | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* eslint mobx/missing-observer: "error" */ | ||
|
||
function Named() { } | ||
const foo = function Named() { } | ||
const Anonym = function () { }; | ||
const Arrow = () => { }; | ||
|
||
observer(function Named() { }); | ||
const foo = observer(function Named() { }) | ||
const Anonym = observer(function () { }); | ||
const Arrow = observer(() => { }); | ||
|
||
function notCmp() { } | ||
const notCmp = function notCmp() { } | ||
const notCmp = function () { } | ||
const notCmp = () => { } | ||
|
||
class Cmp extends React.Component { } | ||
class Cmp extends Component { } | ||
const Cmp = class extends React.Component { } | ||
const Cmp = class extends Component { } | ||
class extends Component { } | ||
class extends React.Component { } | ||
|
||
class NotCmp { } | ||
class NotCmp extends Foo { } | ||
class NotCmp extends React.Foo { } | ||
|
||
const Cmp = observer(class Cmp extends React.Component { }) | ||
const Cmp = observer(class Cmp extends Component { }) | ||
const Cmp = observer(class extends React.Component { }) | ||
const Cmp = observer(class extends Component { }) |
12 changes: 12 additions & 0 deletions
12
packages/eslint-plugin-mobx/preview/no-anonymous-observer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* eslint mobx/no-anonymous-observer: "error" */ | ||
|
||
observer(() => { }); | ||
observer(function () { }); | ||
observer(class { }); | ||
|
||
const Cmp = observer(() => { }); | ||
const Cmp = observer(function () { }); | ||
const Cmp = observer(class { }); | ||
|
||
observer(function Name() { }); | ||
observer(class Name { }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
'use strict'; | ||
|
||
function create(context) { | ||
const sourceCode = context.getSourceCode(); | ||
|
||
return { | ||
'FunctionDeclaration,FunctionExpression,ArrowFunctionExpression,ClassDeclaration,ClassExpression': cmp => { | ||
// Already has observer | ||
if (cmp.parent && cmp.parent.type === 'CallExpression' && cmp.parent.callee.name === 'observer') return; | ||
let name = cmp.id?.name; | ||
// If anonymous try to infer name from variable declaration | ||
if (!name && cmp.parent?.type === 'VariableDeclarator') { | ||
name = cmp.parent.id.name; | ||
} | ||
if (cmp.type.startsWith('Class')) { | ||
// Must extend Component or React.Component | ||
const { superClass } = cmp; | ||
if (!superClass) return; | ||
const superClassText = sourceCode.getText(superClass); | ||
if (superClassText !== 'Component' && superClassText !== 'React.Component') return; | ||
} else { | ||
// Name must start with uppercase letter | ||
if (!name?.charAt(0).match(/^[A-Z]$/)) return; | ||
} | ||
|
||
const fix = fixer => { | ||
return [ | ||
fixer.insertTextBefore( | ||
sourceCode.getFirstToken(cmp), | ||
(name && cmp.type.endsWith('Declaration') ? `const ${name} = ` : '') + 'observer(', | ||
), | ||
fixer.insertTextAfter( | ||
sourceCode.getLastToken(cmp), | ||
')', | ||
), | ||
] | ||
} | ||
context.report({ | ||
node: cmp, | ||
messageId: 'missingObserver', | ||
data: { | ||
name: name || '<anonymous>', | ||
}, | ||
fix, | ||
}) | ||
}, | ||
}; | ||
} | ||
|
||
module.exports = { | ||
meta: { | ||
type: 'problem', | ||
fixable: 'code', | ||
docs: { | ||
description: 'prevents missing `observer` on react component', | ||
recommended: true, | ||
}, | ||
messages: { | ||
missingObserver: "Component `{{ name }}` is missing `observer`.", | ||
}, | ||
}, | ||
create, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
'use strict'; | ||
|
||
function create(context) { | ||
const sourceCode = context.getSourceCode(); | ||
|
||
return { | ||
'CallExpression[callee.name="observer"]': observer => { | ||
const cmp = observer.arguments[0]; | ||
if (!cmp) return; | ||
if (cmp?.id?.name) return; | ||
|
||
const fix = fixer => { | ||
// Use name from variable for autofix | ||
const name = observer.parent?.type === 'VariableDeclarator' | ||
? observer.parent.id.name | ||
: undefined; | ||
|
||
if (!name) return; | ||
if (cmp.type === 'ArrowFunctionExpression') { | ||
const arrowToken = sourceCode.getTokenBefore(cmp.body); | ||
return [ | ||
fixer.replaceText(arrowToken, ''), | ||
fixer.insertTextBefore(cmp, `function ${name}`), | ||
] | ||
} | ||
if (cmp.type === 'FunctionExpression') { | ||
const functionToken = sourceCode.getFirstToken(cmp); | ||
return fixer.replaceText(functionToken, `function ${name}`); | ||
} | ||
if (cmp.type === 'ClassExpression') { | ||
const classToken = sourceCode.getFirstToken(cmp); | ||
return fixer.replaceText(classToken, `class ${name}`); | ||
} | ||
} | ||
context.report({ | ||
node: cmp, | ||
messageId: 'observerComponentMustHaveName', | ||
fix, | ||
}) | ||
}, | ||
}; | ||
} | ||
|
||
module.exports = { | ||
meta: { | ||
type: 'problem', | ||
fixable: 'code', | ||
docs: { | ||
description: 'forbids anonymous functions or classes as `observer` components', | ||
recommended: true, | ||
}, | ||
messages: { | ||
observerComponentMustHaveName: "`observer` component must have a name.", | ||
}, | ||
}, | ||
create, | ||
}; |
Oops, something went wrong.