eslint-plugin-task-needs-wait-for
Version:
Helps to prevent writing ember-concurrency tasks that would create flaky tests.
79 lines (74 loc) • 2.27 kB
text/typescript
import {
AST_NODE_TYPES,
TSESTree,
ESLintUtils,
} from "@typescript-eslint/utils";
const TASKS = [
"task",
"restartableTask",
"dropTask",
"keepLatestTask",
"enqueueTask",
];
const WAIT_FOR = "waitFor";
const WAIT_FOR_D = `@${WAIT_FOR}`;
const ERR_TASK_BEFORE_WAIT_FOR =
"@task has to be always before @waitFor - https://github.com/emberjs/ember-test-waiters#waitfor-function";
const createRule = ESLintUtils.RuleCreator((name) => `decorator-order`);
type Options = [];
type MessageIds = "task-before-wait-for";
export const decoratorOrder = createRule<Options, MessageIds>({
create(context) {
return {
["MethodDefinition:has([decorators])"](node: TSESTree.Node) {
if (node.type === AST_NODE_TYPES.MethodDefinition) {
// TODO: No idea why, but this does not work: https://typescript-eslint.io/developers/custom-rules#explicit-node-types
// @ts-ignore
const decorators = node.decorators.map((d) => d.expression.name);
const taskPosition = decorators.findIndex((elm) =>
TASKS.includes(elm),
);
const waitForPosition = decorators.findIndex(
(elm) => elm === WAIT_FOR,
);
if (
taskPosition > -1 &&
waitForPosition > -1 &&
taskPosition > waitForPosition
) {
context.report({
node: node.decorators[taskPosition],
messageId: "task-before-wait-for",
*fix(fixer) {
// @ts-ignore
const swap = node.decorators[taskPosition].expression.name;
yield fixer.replaceText(
node.decorators[taskPosition],
WAIT_FOR_D,
);
yield fixer.replaceText(
node.decorators[waitForPosition],
`@${swap}`,
);
},
});
return;
}
}
},
};
},
name: "decorator-order",
meta: {
docs: {
description: "@task should be before @waitFor",
},
messages: {
"task-before-wait-for": ERR_TASK_BEFORE_WAIT_FOR,
},
type: "suggestion",
schema: [],
fixable: "code",
},
defaultOptions: [],
});