Skip to content

Commit

Permalink
feat(eslint-plugin): complete wrap-schedule-instead-of-ctx-schedule-r…
Browse files Browse the repository at this point in the history
…ule (#845)
  • Loading branch information
serikovlearning committed Oct 4, 2024
1 parent ec71d33 commit c4d044d
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/eslint-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
{
"name": "pivaszbs",
"url": "https://github.com/pivaszbs"
},
{
"name": "serikovlearning",
"url": "https://github.com/serikovlearning"
}
],
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
import './rules/unit-naming-rule.test'
import './rules/async-rule.test'
import './rules/wrap-schedule-instead-of-ctx-schedule-rule.test'
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { ESLint } from 'eslint'
import { asyncRule } from './rules/async-rule'
import { unitNamingRule } from './rules/unit-naming-rule'
import { deprecateCtxScheduleRule } from './rules/wrap-schedule-instead-of-ctx-schedule-rule'

const rules = {
'unit-naming-rule': unitNamingRule,
'async-rule': asyncRule,
'deprecate-ctx-schedule-rule': deprecateCtxScheduleRule,
}

export default {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { deprecateCtxScheduleRule } from "./wrap-schedule-instead-of-ctx-schedule-rule";

const { RuleTester } = require("eslint");


const tester = new RuleTester({
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
},
})

tester.run(
"wrap-schedule-instead-ctx-schedule",
deprecateCtxScheduleRule,
{
valid: [
{
code: `import { wrap } from "@reatom/framework";\nwrap(ctx, () => {})`,
},
{
code: `import { wrap } from "@reatom/framework";\nwrap(ctx, () => 'Dev')`,
},
{
code: `import { schedule } from "@reatom/framework";\nschedule(ctx, () => 'Dev', -1)`,
},
{
code: `import { schedule } from "@reatom/framework";\nschedule(ctx, () => 'Dev', -1)`,
},

],
invalid: [
{
code: "ctx.schedule()",
output: `import { wrap } from "@reatom/framework";\nwrap(ctx, () => {})`,
errors: [{message: "Use 'wrap(ctx, cb)' instead of deprecated 'ctx.schedule(cb, n)'."}]
},
{
code: "ctx.schedule(() => 'Dev')",
output: `import { wrap } from "@reatom/framework";\nwrap(ctx, () => 'Dev')`,
errors: [{message: "Use 'wrap(ctx, cb)' instead of deprecated 'ctx.schedule(cb, n)'."}]
},
{
code: "ctx.schedule(() => 'Dev', -1)",
output: `import { schedule } from "@reatom/framework";\nschedule(ctx, () => 'Dev', -1)`,
errors: [{message: "Use 'schedule(ctx, cb, n)' instead of deprecated 'ctx.schedule(cb, n)'."}]
},
{
code: `import { schedule } from "@reatom/framework";\nctx.schedule(() => 'Dev', -1)`,
output: `import { schedule } from "@reatom/framework";\nschedule(ctx, () => 'Dev', -1)`,
errors: [{message: "Use 'schedule(ctx, cb, n)' instead of deprecated 'ctx.schedule(cb, n)'."}]
},
],
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import * as estree from 'estree'
import { Rule } from 'eslint'
import { checkCallExpressionNode } from '../shared'

const importsMap = {
wrap: 'import { wrap } from "@reatom/framework";\n',
schedule: 'import { schedule } from "@reatom/framework";\n',
}

const getTextToReplace = (nText: string, callbackText: string) => {
if (Boolean(nText)) {
return `schedule(ctx, ${callbackText}, ${nText})`
}
return `wrap(ctx, ${callbackText})`
}

const getMessage = (n?: estree.Expression | estree.SpreadElement) => {
if (Boolean(n)) {
return "Use 'schedule(ctx, cb, n)' instead of deprecated 'ctx.schedule(cb, n)'."
}

return "Use 'wrap(ctx, cb)' instead of deprecated 'ctx.schedule(cb, n)'."
}

const isImportICareAbout = (node: estree.ImportDeclaration) => {
return node.specifiers.some(
(specifier) =>
specifier.type === 'ImportSpecifier' &&
(specifier.imported.name === 'wrap' || specifier.imported.name === 'schedule') &&
node.source.value === '@reatom/framework',
)
}

export const deprecateCtxScheduleRule: Rule.RuleModule = {
meta: {
type: 'suggestion',
docs: {
description: "Method 'ctx.schedule' is deprecated in v4",
},
fixable: 'code',
hasSuggestions: true,
schema: [],
},
create(context) {
let hasImport = false
let lastImport: estree.ImportDeclaration | null = null

return {
ImportDeclaration(node: estree.ImportDeclaration) {
lastImport = node
if (isImportICareAbout(node)) {
hasImport = true
}
},

CallExpression(node: estree.CallExpression) {
if (checkCallExpressionNode(node)) {
let cb = node.arguments[0]
let n = node.arguments[1]

context.report({
node,
message: getMessage(n),
fix(fixer) {
const fixes = []
const sourceCode = context.sourceCode

const callbackText = cb ? sourceCode.getText(cb) : '() => {}'
const nText = n ? sourceCode.getText(n) : ''

fixes.push(fixer.replaceText(node, getTextToReplace(nText, callbackText)))

if (!hasImport) {
const newImport = importsMap[n ? 'schedule' : 'wrap']
fixes.push(
lastImport
? fixer.insertTextBefore(lastImport, newImport)
: fixer.insertTextAfterRange([0, 0], newImport),
)
}

return fixes
},
})
}
},
}
},
}
5 changes: 5 additions & 0 deletions packages/eslint-plugin/src/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ export const patternNames = (pattern: estree.Pattern): estree.Identifier[] => {
}
return []
}

export const checkCallExpressionNode = (node: estree.CallExpression) =>
node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.property.type === 'Identifier'

0 comments on commit c4d044d

Please sign in to comment.