diff --git a/README.md b/README.md index 3aadb51..2c42ed3 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Configure it in `package.json`. "ramda/complement-simplification": "error", "ramda/compose-pipe-style": "error", "ramda/compose-simplification": "error", + "ramda/cond-default": "error", "ramda/cond-simplification": "error", "ramda/either-simplification": "error", "ramda/eq-by-simplification": "error", @@ -67,6 +68,7 @@ Configure it in `package.json`. - `complement-simplification` - Forbids confusing `complement`, suggesting a better one - `compose-pipe-style` - Enforces `compose` for single line expression and `pipe` for multiline - `compose-simplification` - Detects when a function that has the same behavior already exists +- `cond-default` - Enforces `cond` having `R.T` as the last condition - `cond-simplification` - Forbids using `cond` when `ifElse`, `either` or `both` fits - `either-simplification` - Suggests transforming negated `either` conditions on negated `both` - `eq-by-simplification` - Forbids `eqBy(prop(_))` and suggests `eqProps` diff --git a/rules/cond-default.js b/rules/cond-default.js new file mode 100644 index 0000000..c487287 --- /dev/null +++ b/rules/cond-default.js @@ -0,0 +1,43 @@ +'use strict'; +const R = require('ramda'); +const ast = require('../ast-helper'); + +const isCalling = ast.isCalling; +const isRamdaMethod = ast.isRamdaMethod; + +const create = context => ({ + CallExpression(node) { + const match = isCalling({ + name: 'cond', + arguments: R.tryCatch( + R.pipe( + R.head, + R.prop('elements'), + R.last, + R.prop('elements'), + R.head, + isRamdaMethod('T'), + R.not + ), + R.F + ) + }); + + if (match(node)) { + context.report({ + node, + message: '`cond` should finish with a `T` condition so it returns a default value' + }); + } + } +}); + +module.exports = { + create, + meta: { + docs: { + description: '`cond` default, like suggesting returning a default value', + recommended: 'error' + } + } +}; diff --git a/test/cond-default.js b/test/cond-default.js new file mode 100644 index 0000000..5d9b6a6 --- /dev/null +++ b/test/cond-default.js @@ -0,0 +1,37 @@ +import test from 'ava'; +import avaRuleTester from 'eslint-ava-rule-tester'; +import rule from '../rules/cond-default'; + +const ruleTester = avaRuleTester(test, { + env: { + es6: true + }, + parserOptions: { + sourceType: 'module' + } +}); + +const error = { + ruleId: 'cond-default', + message: '`cond` should finish with a `T` condition so it returns a default value' +}; + +ruleTester.run('cond-default', rule, { + valid: [ + 'cond([[a, b], [T, d]])', + 'R.cond([[a, b], [R.T, d]])', + 'cond([[a, b], [c, d], [T, f]])', + 'R.cond([[a, b], [c, d], [R.T, f]])', + 'cond(anything)' + ], + invalid: [ + { + code: 'cond([[a, b], [c, d]])', + errors: [error] + }, + { + code: 'cond([[a, b], [c, d], [e, f]])', + errors: [error] + } + ] +});