UNPKG

eslint-plugin-task-needs-wait-for

Version:

Helps to prevent writing ember-concurrency tasks that would create flaky tests.

89 lines (85 loc) 2.89 kB
import { AST_NODE_TYPES, ESLintUtils, TSESTree, } from "@typescript-eslint/utils"; const TASKS = [ "task", "restartableTask", "dropTask", "keepLatestTask", "enqueueTask", ]; const WAIT_FOR = "waitFor"; const WAIT_FOR_D = `@${WAIT_FOR}`; const IMPORT_D = `import { waitFor } from '@ember/test-waiters';`; const ERR_TASK_WITHOUT_WAIT_FOR = "@task usage without @waitFor can be a cause of promises not being awaited for in tests. That is why every usage of @task should be accompanied with @waitFor - https://github.com/emberjs/ember-test-waiters#waitfor-function"; const createRule = ESLintUtils.RuleCreator((name) => `decorator-presence`); // Type: RuleModule<"uppercase", ...> export const decoratorPresence = createRule({ 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) { if (waitForPosition === -1) { context.report({ node, messageId: "task-without-wait-for", *fix(fixer) { yield fixer.insertTextAfter( node.decorators[taskPosition], " ", ); yield fixer.insertTextAfter( node.decorators[taskPosition], WAIT_FOR_D, ); const top = context?.getAncestors()?.[0]; // @ts-ignore const hasImport = top?.body.some((elm) => { return ( elm.type === "ImportDeclaration" && elm.specifiers && elm.specifiers.some( // @ts-ignore (spec) => spec?.local?.name === "waitFor", ) ); }); if (!hasImport) { yield fixer.insertTextBefore(top, IMPORT_D); } }, }); return; } } } }, }; }, name: "decorator-presence", meta: { docs: { description: "@task should be accompanied by @waitFor", }, messages: { "task-without-wait-for": ERR_TASK_WITHOUT_WAIT_FOR, }, type: "suggestion", schema: [], fixable: "code", }, defaultOptions: [], });