Skip to content

Commit

Permalink
feat: create no-deprecated-functions rule
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Rath committed May 3, 2020
1 parent f6e0bd0 commit b00f769
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 0 deletions.
43 changes: 43 additions & 0 deletions docs/rules/no-deprecated-functions.md
@@ -0,0 +1,43 @@
# Warns on usage of deprecated functions (no-deprecated-functions)

Over the years jest has accrued some debt in the form of functions that have
either been renamed for clarity, or replaced with more powerful APIs.

While typically these deprecated functions are kept in the codebase for a number
of majors, eventually they are removed completely.

## Rule details

This rule warns about calls to deprecated functions, and provides details on
what to replace them with.

This rule can also autofix a number of these deprecations for you.

### `require.requireActual.` & `require.requireMock`

These functions were removed in Jest 26.

Originally in the early days of jest, the `requireActual`& `requireMock`
functions were placed onto the `require` function.

These functions were later moved onto the `jest` global, and their use via
`require` deprecated. Finally, the release of Jest 26 saw them removed from the
`require` function all together.

The PR implementing the removal can be found
[here](https://github.com/facebook/jest/pull/9854).

### `jest.addMatchers`

This function has been replaced with `expect.extend`, and will ideally be
removed in Jest 27.

### `jest.resetModuleRegistry`

This function has been renamed to `resetModules`, and will ideally be removed in
Jest 27.

### `jest.runTimersToTime`

This function has been renamed to `advanceTimersByTime`, and will ideally be
removed in Jest 27.
41 changes: 41 additions & 0 deletions src/rules/__tests__/no-deprecated-functions.ts
@@ -0,0 +1,41 @@
import { TSESLint } from '@typescript-eslint/experimental-utils';
import rule from '../no-deprecated-functions';

const ruleTester = new TSESLint.RuleTester();

[
['require.requireMock', 'jest.requireMock'],
['require.requireActual', 'jest.requireActual'],
['jest.addMatchers', 'expect.extend'],
['jest.resetModuleRegistry', 'jest.resetModules'],
['jest.runTimersToTime', 'jest.advanceTimersByTime'],
].forEach(([deprecation, replacement]) => {
const [deprecatedName, deprecatedFunc] = deprecation.split('.');
const [replacementName, replacementFunc] = replacement.split('.');

ruleTester.run(`${deprecation} -> ${replacement}`, rule, {
valid: [`${replacement}()`, replacement],
invalid: [
{
code: `${deprecation}()`,
output: `${replacement}()`,
errors: [
{
messageId: 'deprecatedFunction',
data: { deprecation, replacement },
},
],
},
{
code: `${deprecatedName}['${deprecatedFunc}']()`,
output: `${replacementName}['${replacementFunc}']()`,
errors: [
{
messageId: 'deprecatedFunction',
data: { deprecation, replacement },
},
],
},
],
});
});
71 changes: 71 additions & 0 deletions src/rules/no-deprecated-functions.ts
@@ -0,0 +1,71 @@
import {
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/experimental-utils';
import { createRule, getNodeName } from './utils';

export default createRule({
name: __filename,
meta: {
docs: {
category: 'Best Practices',
description: 'Warns on usage of deprecated functions',
recommended: false,
},
messages: {
deprecatedFunction:
'`{{ deprecation }}` has been deprecated in favor of `{{ replacement }}`',
},
type: 'suggestion',
schema: [],
fixable: 'code',
},
defaultOptions: [],
create(context) {
const deprecations: Record<string, string> = {
'require.requireMock': 'jest.requireMock',
'require.requireActual': 'jest.requireActual',
'jest.addMatchers': 'expect.extend',
'jest.resetModuleRegistry': 'jest.resetModules',
'jest.runTimersToTime': 'jest.advanceTimersByTime',
};

return {
CallExpression(node: TSESTree.CallExpression) {
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) {
return;
}

const deprecation = getNodeName(node);

if (!deprecation || !(deprecation in deprecations)) {
return;
}

const replacement = deprecations[deprecation];
const { callee } = node;

context.report({
messageId: 'deprecatedFunction',
data: {
deprecation,
replacement,
},
node,
fix(fixer) {
let [name, func] = replacement.split('.');

if (callee.property.type === AST_NODE_TYPES.Literal) {
func = `'${func}'`;
}

return [
fixer.replaceText(callee.object, name),
fixer.replaceText(callee.property, func),
];
},
});
},
};
},
});

0 comments on commit b00f769

Please sign in to comment.