Skip to content

Commit b00f769

Browse files
committed
feat: create no-deprecated-functions rule
1 parent f6e0bd0 commit b00f769

File tree

3 files changed

+155
-0
lines changed

3 files changed

+155
-0
lines changed

docs/rules/no-deprecated-functions.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Warns on usage of deprecated functions (no-deprecated-functions)
2+
3+
Over the years jest has accrued some debt in the form of functions that have
4+
either been renamed for clarity, or replaced with more powerful APIs.
5+
6+
While typically these deprecated functions are kept in the codebase for a number
7+
of majors, eventually they are removed completely.
8+
9+
## Rule details
10+
11+
This rule warns about calls to deprecated functions, and provides details on
12+
what to replace them with.
13+
14+
This rule can also autofix a number of these deprecations for you.
15+
16+
### `require.requireActual.` & `require.requireMock`
17+
18+
These functions were removed in Jest 26.
19+
20+
Originally in the early days of jest, the `requireActual`& `requireMock`
21+
functions were placed onto the `require` function.
22+
23+
These functions were later moved onto the `jest` global, and their use via
24+
`require` deprecated. Finally, the release of Jest 26 saw them removed from the
25+
`require` function all together.
26+
27+
The PR implementing the removal can be found
28+
[here](https://github.com/facebook/jest/pull/9854).
29+
30+
### `jest.addMatchers`
31+
32+
This function has been replaced with `expect.extend`, and will ideally be
33+
removed in Jest 27.
34+
35+
### `jest.resetModuleRegistry`
36+
37+
This function has been renamed to `resetModules`, and will ideally be removed in
38+
Jest 27.
39+
40+
### `jest.runTimersToTime`
41+
42+
This function has been renamed to `advanceTimersByTime`, and will ideally be
43+
removed in Jest 27.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { TSESLint } from '@typescript-eslint/experimental-utils';
2+
import rule from '../no-deprecated-functions';
3+
4+
const ruleTester = new TSESLint.RuleTester();
5+
6+
[
7+
['require.requireMock', 'jest.requireMock'],
8+
['require.requireActual', 'jest.requireActual'],
9+
['jest.addMatchers', 'expect.extend'],
10+
['jest.resetModuleRegistry', 'jest.resetModules'],
11+
['jest.runTimersToTime', 'jest.advanceTimersByTime'],
12+
].forEach(([deprecation, replacement]) => {
13+
const [deprecatedName, deprecatedFunc] = deprecation.split('.');
14+
const [replacementName, replacementFunc] = replacement.split('.');
15+
16+
ruleTester.run(`${deprecation} -> ${replacement}`, rule, {
17+
valid: [`${replacement}()`, replacement],
18+
invalid: [
19+
{
20+
code: `${deprecation}()`,
21+
output: `${replacement}()`,
22+
errors: [
23+
{
24+
messageId: 'deprecatedFunction',
25+
data: { deprecation, replacement },
26+
},
27+
],
28+
},
29+
{
30+
code: `${deprecatedName}['${deprecatedFunc}']()`,
31+
output: `${replacementName}['${replacementFunc}']()`,
32+
errors: [
33+
{
34+
messageId: 'deprecatedFunction',
35+
data: { deprecation, replacement },
36+
},
37+
],
38+
},
39+
],
40+
});
41+
});

src/rules/no-deprecated-functions.ts

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import {
2+
AST_NODE_TYPES,
3+
TSESTree,
4+
} from '@typescript-eslint/experimental-utils';
5+
import { createRule, getNodeName } from './utils';
6+
7+
export default createRule({
8+
name: __filename,
9+
meta: {
10+
docs: {
11+
category: 'Best Practices',
12+
description: 'Warns on usage of deprecated functions',
13+
recommended: false,
14+
},
15+
messages: {
16+
deprecatedFunction:
17+
'`{{ deprecation }}` has been deprecated in favor of `{{ replacement }}`',
18+
},
19+
type: 'suggestion',
20+
schema: [],
21+
fixable: 'code',
22+
},
23+
defaultOptions: [],
24+
create(context) {
25+
const deprecations: Record<string, string> = {
26+
'require.requireMock': 'jest.requireMock',
27+
'require.requireActual': 'jest.requireActual',
28+
'jest.addMatchers': 'expect.extend',
29+
'jest.resetModuleRegistry': 'jest.resetModules',
30+
'jest.runTimersToTime': 'jest.advanceTimersByTime',
31+
};
32+
33+
return {
34+
CallExpression(node: TSESTree.CallExpression) {
35+
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) {
36+
return;
37+
}
38+
39+
const deprecation = getNodeName(node);
40+
41+
if (!deprecation || !(deprecation in deprecations)) {
42+
return;
43+
}
44+
45+
const replacement = deprecations[deprecation];
46+
const { callee } = node;
47+
48+
context.report({
49+
messageId: 'deprecatedFunction',
50+
data: {
51+
deprecation,
52+
replacement,
53+
},
54+
node,
55+
fix(fixer) {
56+
let [name, func] = replacement.split('.');
57+
58+
if (callee.property.type === AST_NODE_TYPES.Literal) {
59+
func = `'${func}'`;
60+
}
61+
62+
return [
63+
fixer.replaceText(callee.object, name),
64+
fixer.replaceText(callee.property, func),
65+
];
66+
},
67+
});
68+
},
69+
};
70+
},
71+
});

0 commit comments

Comments
 (0)