Giter VIP home page Giter VIP logo

eslint-plugin-fp's Introduction

eslint-plugin-fp Build Status

ESLint rules for functional programming

Install

$ npm install --save-dev eslint eslint-plugin-fp

Usage

Configure it in package.json.

{
  "name": "my-awesome-project",
  "eslintConfig": {
    "env": {
      "es6": true
    },
    "plugins": [
      "fp"
    ],
    "rules": {
      "fp/no-arguments": "error",
      "fp/no-class": "error",
      "fp/no-delete": "error",
      "fp/no-events": "error",
      "fp/no-get-set": "error",
      "fp/no-let": "error",
      "fp/no-loops": "error",
      "fp/no-mutating-assign": "error",
      "fp/no-mutating-methods": "error",
      "fp/no-mutation": "error",
      "fp/no-nil": "error",
      "fp/no-proxy": "error",
      "fp/no-rest-parameters": "error",
      "fp/no-this": "error",
      "fp/no-throw": "error",
      "fp/no-unused-expression": "error",
      "fp/no-valueof-field": "error",
      "no-var": "error"
    }
  }
}

Rules

Recommended configuration

This plugin exports a recommended configuration that enforces good practices.

To enable this configuration, use the extends property in your package.json.

{
  "name": "my-awesome-project",
  "eslintConfig": {
    "plugins": [
      "fp"
    ],
    "extends": "plugin:fp/recommended"
  }
}

See ESLint documentation for more information about extending configuration files.

MIT Β© Jeroen Engels

eslint-plugin-fp's People

Contributors

arcanemagus avatar graingert avatar jfmengels avatar joshburgess avatar macklinu avatar nickmccurdy avatar viatsko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eslint-plugin-fp's Issues

Fails when run in Jest via ESLint Node.js API

This demo shows that eslint-plugin-fp doesn't seem to work when run in Jest via ESLint Node.js API, ESLint reports an error for every fp/* rule, for example:

Definition for rule 'fp/no-let' was not found  fp/no-let

as if I didn't add fp to plugins in my ESLint configuration.

  • this only happens with eslint-plugin-fp, I threw eslint-plugin-import in there, too, and it works
  • this only happens in combination with Jest, try running yarn script which also runs ESLint via Node.js API, and it works

That's as far as I got. πŸ˜„

Rule proposal: return-in-conditionals

Conditionals (in functions) that don't return a value or end the function are most likely causing a side-effect.
In the case when it is used to assign a value to a variable, in order to not have a complex ternary expression, should probably be moved to a separate function.

Switch cases should also return statement and should therefore not use break.

Top-level conditionals should be exempted from this rule, as they can't return values. (bikeshedding here?)

Invalid

function bar(a) {
  let res;
  if (expression) {
    res = 2;
  } else {
    res = 3;
  }
  return foo(res);
}

function switchFn(b) {
  switch(a) {
    case 1:
       doSomething();
       break;
    default:
       doSomethingElse();
       break;
  }
}

Valid

function bar(a) {
  return foo(value(a));
}

function value(a) {
  if (expression) {
    return 2;
  } else {
    return 3;
  }
}

function switchFn(b) {
  switch(a) {
    case 1:
       return doSomething();
    default:
       return doSomethingElse();
  }
}

// Top-level conditionals are okay
if (FOO) {
  foo();
} else {
  bar();
}

Disallow array mutation

Mutative array methods, such as push, are not disabled by this library yet. That would be a nice addition.

PropTypes for stateless components

Hi πŸ‘‹ ,

First off, great plugin! I was wondering if you'd accept a PR modifying fp/no-mutation to allow for a pattern such as this:

import React from 'react'

const Component = (props) => <div>{props.name}</div>

Component.propTypes = { name: React.PropTypes.string.isRequired }

export default Component

There doesn't seem to be a different way to define propType validation and use stateless components at the same time.

no-nil false positive on switch statements

Take this function:

const someFunction = (state, action) => {
  switch (action.type) {
    case 'SOME_ACTION': {
      return assoc('anything', true, state);
    }
    default: {
      return state;
    }
  }
}

fp/no-nil complains about it. Am I missing something or this should not have an error on it?

Add a config that's more lenient for OOP

I understand the recommended config's decision to ban classes, but this plugin exposes a lot of useful options to allow OOP style while preventing too much mutation outside of object construction. I think it would be useful to expose a plugin:fp/oop config with classes, this mutation, and similar options enabled.

If you agree I can make a pull request (and just to be clear, this would not be the default config).

Add more options for `no-unused-expression` rule

Currently, i almost don't see how it can be used, even in FP. It's true that i'm not so fully FP, not so hardcore FP, but it fails for simple things like asserting. Isn't it too aggressive?

Can you should some "real" examples that may pass that rule? It's pretty cool and i like it, mostly.

no-mutating-methods sort after concat

Was just wondering if there would be a way to enable a mutating method like .sort() only after a method that returns a new array such as .map(), .filter(), .concat() etc.
So you could do

// mutates original array
myarray.sort()

// doesn't mutate original array
myarray.concat().sort()

non-mutating slice reverse

it would be nice if .slice().reverse() (usual way to reverse without mutating) where not breaking the fp/no-mutating-methods rule (as .reverse() does).

fp/no-unused-expression for Node debug

Node debug is making fp/no-unused-expression unhappy because it's a noop. Is there a way to say "Yo, this is like console, he's a cool noop..." or do I just // eslint-disable-line for all debugs?

no-nil false positive

 switch (ham) {
    case "spam": return 3;
    case blockTypes.skew:
    default: return 4;
  }

should pass

same with:

if (foo) {
    return 3;
} else {
    return 4;
}

I've made a PR to fix eslint-plugin-better's explicit-return rule: idmitriev/eslint-plugin-better#3 using the consistent-return rule from eslint core

proposal: rule for limit arguments in function call

Something like this:

const create = function (context) {
  return {
    CallExpression (node) {
      const limit = context.options[0]
      if (limit >= 0 && node.arguments.length > limit) {
        context.report({
          node,
          message: 'invalid call expression (too many arguments)',
        })
      }
    }
  }
}
// example if configured to accept only 1 argument or less
func () // ok
func (1) // ok
func (1, 2) // error

// example if configured to accept only 3 argument or less
func ([ 1, 2 ], 3) // ok
func ([ 1, 2 ], 3, 4, () => 5) // error

no-mutation and HTML DOM

Currently, no-mutation will flag code like this:

document.title = "A new title";

I propose adding an option, similar to the commonjs option, which allows DOM mutations. Since there’s no non-mutating way to set those DOM properties, the only error-free way of doing it now seems to be to manually add exceptions in .eslintrc.

How to deal with unused-expressions

Node.js is full of unused expressions.

For example, If I call setHeader on a ClientRequest I have a non-useful return.

There are things like Eff or Io to model side-effects; Is the best approach to disable eslint checking for unused expressions inside these monads?

Rules tend to be noisy in test frameworks

Popular test frameworks like Mocha, Jasmine, and Jest encourage having many anonymous functions with assertions instead of return values. While this is inherently not a very functional paradigm, many functional libraries still use these test frameworks and it can be inconvenient to batch disable many rules at once.

Possible solutions

  1. Tell users to disable eslint in the test directory with an .eslintignore file. This is pretty drastic, but if we agree on this it wouldn't require any changes.
  2. Provide a configuration that disables all rules from this plugin. Unfortunately, eslint doesn't have an option for disabling all of a plugin's rules (see eslint/eslint#3419), so this would be a workaround.
  3. Provide a configuration that's similar to recommended, but friendlier to anonymous functions with assertions. This could disable rules like no-nil and no-unused-expressions. Users would then switch to this configuration only for test directories.

CI build failing on Node 4

Introduced by https://travis-ci.org/jfmengels/eslint-plugin-fp/jobs/167645907

$ npm test
> [email protected] test /home/travis/build/jfmengels/eslint-plugin-fp
> xo && nyc ava
Error: Failed to load plugin no-use-extend-native: Cannot find module 'eslint-plugin-no-use-extend-native'
Referenced from: 
    at Function.Module._resolveFilename (module.js:325:15)
    at Function.Module._load (module.js:276:25)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Object.load (/home/travis/build/jfmengels/eslint-plugin-fp/node_modules/eslint/lib/config/plugins.js:129:26)
    at Array.forEach (native)
    at Object.loadAll (/home/travis/build/jfmengels/eslint-plugin-fp/node_modules/eslint/lib/config/plugins.js:151:21)
    at load (/home/travis/build/jfmengels/eslint-plugin-fp/node_modules/eslint/lib/config/config-file.js:504:21)
    at /home/travis/build/jfmengels/eslint-plugin-fp/node_modules/eslint/lib/config/config-file.js:391:36
    at Array.reduceRight (native)
npm ERR! Test failed.  See above for more details.

no-mutating-methods allowedObjects doesn't work if chained

The following will pass:

/* eslint fp/no-mutating-methods: ["error", {"allowedObjects": ["mongo"]}] */
mongo.sort()

Whereas the following will fail:

/* eslint fp/no-mutating-methods: ["error", {"allowedObjects": ["mongo"]}] */
mongo.collection().sort()

I'd like to see both pass, but maybe this is by design?

no-nil doesn't seem to understand default switch case

const reducer = (state = {}, action) => {
  switch (action.type) {
    case 'CHANGE_TEXT':
      return { text: action.payload };
    default:
      return state;
  }
};

This function will always return something, but sadly I get the error Function must end with a return statement, so that it doesn't return undefined fp/no-nil.

Support ESLint 8.x

ESLint v8.0.0 is released πŸŽ‰

It would be awesome to have official ESLint 8 support. πŸ‘Š
I'm happy to help where I can of course πŸ™‚

Add `no-arguments` rule

This rule would forbid the use of the arguments variable implicitly given to the context of a function

Fail

function foo() {
  console.log(arguments);
}

Valid

function foo(a, b) {
  // anything not using arguments
}

I wonder whether the spread arguments should also be forbidden, probably either behind a flag or in an other rule (my current favorite option at the moment), as it does not work well with currying.

Fail

function foo(...args) {
}

Valid

function foo(args) { // passed as an array
}

Does anybody have any thoughts on this? Open to bikeshedding :)

Rule proposal: no-functions-without-parameters

Rule proposal: Forbid functions that do not take parameters.

Functions that do not take parameters are either

  • using arguments to do some odd behavior. There is a different rule for that, but still
  • has side-causes : uses variables besides closure variables or parameters
  • always return the same value: The function call could be replaced by the value itself.

I do wonder about methods that are not assigned, like for the following example

const count = values
  .map(() => 1)
  .reduce((a, b) => a + b, 0);

This should be allowed, and I think that having the function not be assigned and not declared on its own (i.e., passed as an expression) should be allowed, but I'm not sure whether this should be behind a flag or not.

If people are watching, would gladly get some feedback on this :)

RCF: 'Pure' rule

Would a 'pure' that enforced functional purity be a welcome addition to this project?

allow reassigment for variables

I can't enforce variables reassignment for actual project, but I can enforce it on object. It is possible to turn-off variables reassignment somehow?

no-mutating-assign with any expression

Thanks for this excellent plugin. Further to #17, I wonder if you'd consider allowing any function call as the first argument to Object.assign() (or at least add an option to allow this). For example, I think this would always be "functionally safe":

Object.assign(anyFunctionCall(_), {prop: 'value'})

If you're happy with the concept I'm happy to PR (although any hint you can give about what the eslint type of a function call would be, would be very helpful, as I've never written an eslint rule before)!

Is no-nill too strict?

Hi all! Thanks for this awesome eslint plugin!
I can't use null in objects, is that a bug or an expected behaviour? How can I solve this?

const defaultState = {
    token: null
}
export function reducer(state = defaultState, action){
    return state
}

/home/user/Scrivania/mercury-new/src/modules/auth/index.js
  3:12  error  Unallowed use of `null` or `undefined`  fp/no-nil


fp/no-rest-parameters false-positive

function f(params) {
    const [head, ...tail] = params;
}

produces Unallowed use of rest parameters. Use regular function arguments instead,
but params is a regular function argument (an array).

(fp/no-nil) rule for callbacks?

It is standard to write callbacks with error first so you end up with callback(null, "success message") or callback(err).

Is the solution to get around this to not use callbacks?

Rule proposal: no-valueof-field / no-valueof

Rule proposal: Forbid specifying a valueOf field in an object.

const object = {
  valueOf: () => 2 // or do something odd
};
object+''
// => '2'

Having valueOf overriden for an object, or any value, can cause some unexpected, or simply implicit behavior.

Invalid

const object1 = {
  value: 15,
  valueOf: function() { return this.value; }
};
const object2 = {
  value: 25,
  valueOf: function() { return this.value; }
};
object1 + object2
// => 40

Valid

const addValueOf = (a, b) => a.value + b.value;

const object1 = {
  value: 15
};
const object2 = {
  value: 25
};

addValueOf(object1, object2)
// => 40

I'm wondering whether this should also check for X.prototype.valueOf = ..., X.valueOf = .... I'm not sure as it's already kind of covered by no-mutation, and I'd prefer not to create 2 errors for it. I still think it should (and then the name should be changed, probably to no-valueof) as people can turn on this rule and not no-mutation.

And that brings another question, should no-valueof then also forbid calling valueOf explicitly?

If people are watching, would gladly get some feedback on this :)

fp/no-nil

I propose an option to allow returning nil in array methods like .map(), .filter(), etc.
Because more often than not they are one-liners that don't need explicit return.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.