Giter VIP home page Giter VIP logo

jamiemason / eslint-plugin-prefer-arrow-functions Goto Github PK

View Code? Open in Web Editor NEW
38.0 3.0 8.0 352 KB

Auto-fix plain Functions into Arrow Functions, in all cases where conversion would result in the same behaviour

Home Page: https://www.npmjs.com/package/eslint-plugin-prefer-arrow-functions

License: MIT License

JavaScript 2.12% TypeScript 97.88%
eslint eslint-rule eslint-plugin arrow-functions javascript nodejs linter linting lint codemod

eslint-plugin-prefer-arrow-functions's Introduction

eslint-plugin-prefer-arrow-functions

An ESLint Plugin to Lint and auto-fix plain Functions into Arrow Functions, in all cases where conversion would result in the same behaviour (Arrow Functions do not support this, arguments, or new.target for example).

NPM version NPM downloads Build Status Maintainability

Table of Contents

โ˜๏ธ Installation

npm install --save-dev eslint eslint-plugin-prefer-arrow-functions

๐Ÿ“ Playground

Try it yourself at ASTExplorer.net by pasting code snippets in the top left panel, the results will appear in the bottom right panel.

โš–๏ธ Configuration

Add the plugin to the plugins section and the rule to the rules section in your .eslintrc. The default values for options are listed in this example.

{
  "plugins": ["prefer-arrow-functions"],
  "rules": {
    "prefer-arrow-functions/prefer-arrow-functions": [
      "warn",
      {
        "allowNamedFunctions": false,
        "classPropertiesAllowed": false,
        "disallowPrototype": false,
        "returnStyle": "unchanged",
        "singleReturnOnly": false
      }
    ]
  }
}

๐Ÿค” Options

allowNamedFunctions

If set to true, the rule won't report named functions such as function foo() {}. Anonymous function such as const foo = function() {} will still be reported.

classPropertiesAllowed

When true, functions defined as class instance fields will be converted to arrow functions when doing so would not alter or break their behaviour.

disallowPrototype

When true, functions assigned to a prototype will be converted to arrow functions when doing so would not alter or break their behaviour.

returnStyle

  • When "implicit", arrow functions such as x => { return x; } will be converted to x => x.
  • When "explicit", arrow functions such as x => x will be converted to x => { return x; }.
  • When "unchanged" or not set, arrow functions will be left as they were.

singleReturnOnly

When true, only function declarations which only contain a return statement will be converted. Functions containing block statements will be ignored.

This option works well in conjunction with ESLint's built-in arrow-body-style set to as-needed.

๐Ÿ‘๐Ÿป Credits

This project is a fork of https://github.com/TristonJ/eslint-plugin-prefer-arrow by Triston Jones.

๐Ÿ™‹๐Ÿฝโ€โ™€๏ธ Getting Help

Get help with issues by creating a Bug Report or discuss ideas by opening a Feature Request.

๐Ÿ‘€ Other Projects

If you find my Open Source projects useful, please share them โค๏ธ

  • eslint-formatter-git-log
    ESLint Formatter featuring Git Author, Date, and Hash
  • eslint-plugin-move-files
    Move and rename files while keeping imports up to date
  • ImageOptim-CLI
    Automates ImageOptim, ImageAlpha, and JPEGmini for Mac to make batch optimisation of images part of your automated build process.
  • Jasmine-Matchers
    Write Beautiful Specs with Custom Matchers
  • karma-benchmark
    Run Benchmark.js over multiple Browsers, with CI compatible output
  • self-help
    Interactive Q&A Guides for Web and the Command Line
  • syncpack
    Manage multiple package.json files, such as in Lerna Monorepos and Yarn Workspaces

๐Ÿค“ Author

I'm Jamie Mason from Leeds in England, I began Web Design and Development in 1999 and have been Contracting and offering Consultancy as Fold Left Ltd since 2012. Who I've worked with includes Sky Sports, Sky Bet, Sky Poker, The Premier League, William Hill, Shell, Betfair, and Football Clubs including Leeds United, Spurs, West Ham, Arsenal, and more.

Follow JamieMason on GitHubย ย ย ย ย ย Follow fold_left on Twitter

eslint-plugin-prefer-arrow-functions's People

Contributors

gabmontes avatar jamiemason avatar keithkml avatar marekdedic avatar mikeapr4 avatar mitchell-merry avatar pablen avatar renato-bohler avatar tristonj 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

Watchers

 avatar  avatar  avatar

eslint-plugin-prefer-arrow-functions's Issues

Functions containing dollar signs (`$`) are incorrectly fixed

Description

While validating this plugin against a big codebase, I found an edge case where it auto-fixes incorrectly.

If the function has a dollar sign ($) on its body, it gets incorrectly transformed somehow.

Example 1

export function foo() {
  const bar = '$';
  return bar
};

Gets transformed into an invalid syntax. Notice the lack of the dollar sign, the missing single quote, and the extra semicolon at the end:

export const foo = () => {
  const bar = ';
  return bar
};;

Example 2

If the dollar sign is in backticks:

export function foo() {
  const bar = `$`;
  return bar
};

Then this happens:

export const foo = () => {
  const bar = `(PARAMS)RETURN_TYPE => ;
  return bar
};;

(PARAMS)RETURN_TYPE => is leaking from the writeArrowFunction function somehow

const writeArrowFunction = (node) => {
const { body, isAsync, isGeneric, generic, params, returnType } =
getFunctionDescriptor(node);
return 'ASYNC<GENERIC>(PARAMS)RETURN_TYPE => BODY'
.replace('ASYNC', isAsync ? 'async ' : '')
.replace('<GENERIC>', isGeneric ? generic : '')
.replace('BODY', body)
.replace('RETURN_TYPE', returnType ? returnType : '')
.replace('PARAMS', params.join(', '));
};

Example 3

If there are two dollar signs, then the transformation is different, but still incorrect:

export function foo() {
  const bar = `$$`;
  return bar
};

And this happens:

export const foo = () => {
  const bar = `const foo = ;
  return bar
};;

Suggested Solution

No idea why that happens, so I'd have to investigate. Probably need to escape $ when replacing or something?

Help Needed

I just need time to look into that.

TypeScript return types go missing with --fix

Description

TypeScript return types go missing with --fix.

Original:

function main(): void {
  console.log('main')
}
function notVoid(): number {
  const a = 3
  return a * 2
}

Expected:

const main = (): void => {
  console.log('main')
}
const notVoid = (): number => {
  const a = 3
  return a * 2
}

Actual:

const main = () => {
  console.log('main')
};
const notVoid = () => {
  const a = 3
  return a * 2
};

More intelligent `returnStyle` option

Description

I hope that arrow functions can be forced to convert to implicit style when there is only one line.

const arr = [0, 1, 2]

arr.filter((x) => {
  return x % 2 === 0
})

// โ†“ โ†“ โ†“ โ†“ โ†“ โ†“
arr.filter((x) => x % 2 === 0)

But if there are multiple lines, it can be forced to convert to the explicit style.

export const delay = (timeout) =>
  new Promise((resolve) => {
    setTimeout(() => {
      resolve()
    }, timeout)
  })

// โ†“ โ†“ โ†“ โ†“ โ†“ โ†“
export const delay = (timeout) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve()
    }, timeout)
  })
}

This also makes it easier to extend React functional components.

export const Button = () => (
  <button>
    <span></span>
  </button>
)

// โ†“ โ†“ โ†“ โ†“ โ†“ โ†“
export const Button = () => {
  return (
    <button>
      <span></span>
    </button>
  )
}

ref: eslint/eslint#9062

Suggested Solution

Add a new smart enumeration to the returnStyle option for intelligent judgment.

Functions as Object properties

Description

Create a .js file in an environment with eslint and eslint-plugin-prefer-arrow-functions
create an object with a function as a property:

const myObj = {
  dummyMethod(){
    // ...
  }
}

The plugin will mark (warn / error) the function.

In some cases, we'd like to use functions as object properties.
In my case, I use Vuejs 2, and each component has this error for the data property:

export default {
  data(){
    return {...}
  }
}

Suggested Solution

It could be great if there's an option to add a rule to the rule-section for prop functions

Prevent or ignore overload functions

Description

First and foremost, thank you for the plugin!

Don't know if this should be a bug or a feature issue, but I tried using this plugin and it seems that it also handles overload functions. Related code below:

https://github.com/strangelove-ventures/graz/blob/94eea291ac2b8ce482e06c3182bfddc92c1a557b/packages/graz/src/actions/clients/tendermint.ts#L125-L145

Or a pseudo-code example:

// example overload functions which handles merging objects with respected types
function example(): object;
function example<A extends object>(a: A): object & A;
function example<A extends object, B extends object>(a: A, b: B): object & A & B;

// this function should not be handled by the plugin
export function example(...args: object[]): any {
  // some logic here
}

When running lint fix, this function should not be converted to arrow function because it will break its intended behavior.

Suggested Solution

If it's possible to know if a function is an overload function, ignore the rule.

Help Needed

Since I am not proficient in AST related things, it'd be helpful if someone can guide on how to implement this. I'd love to contribute!

Plugin auto-fix can't handle empty function

I don't think this is a very useful edge case, but I found this error running the plugin.

Returning undefined resolves the problem.

.eslintrs.js

module.exports = {
	'parserOptions': {
		'ecmaVersion': 2018,
		'sourceType': 'module',
	},
	'plugins': [
		'prefer-arrow-functions',
	],
	'rules': {
		'prefer-arrow-functions/prefer-arrow-functions': [
			'error',
			{
				'classPropertiesAllowed': false,
				'disallowPrototype': true,
				'returnStyle': 'unchanged',
				'singleReturnOnly': true,
			},
		],
	},
};

file.js

function test() {
	return;
}

Try to run:

yarn eslint --fix --plugin prefer-arrow-functions file.js 

Error found:

TypeError: Cannot read properties of null (reading 'type')
Occurred while linting /home/pedr/repo/eslint-plugin-prefer-arrow/file.js:1
    at getBodySource (/home/pedr/repo/eslint-plugin-prefer-arrow/node_modules/eslint-plugin-prefer-arrow-functions/dist/prefer-arrow-functions.js:57:36)
    at getFunctionDescriptor (/home/pedr/repo/eslint-plugin-prefer-arrow/node_modules/eslint-plugin-prefer-arrow-functions/dist/prefer-arrow-functions.js:128:23)
    at writeArrowConstant (/home/pedr/repo/eslint-plugin-prefer-arrow/node_modules/eslint-plugin-prefer-arrow-functions/dist/prefer-arrow-functions.js:121:24)
    at Object.fix (/home/pedr/repo/eslint-plugin-prefer-arrow/node_modules/eslint-plugin-prefer-arrow-functions/dist/prefer-arrow-functions.js:243:60)
    at normalizeFixes (/home/pedr/repo/eslint-plugin-prefer-arrow/node_modules/eslint/lib/linter/report-translator.js:178:28)
    at /home/pedr/repo/eslint-plugin-prefer-arrow/node_modules/eslint/lib/linter/report-translator.js:343:49
    at Object.report (/home/pedr/repo/eslint-plugin-prefer-arrow/node_modules/eslint/lib/linter/linter.js:905:41)
    at FunctionDeclaration[parent.type!="ExportDefaultDeclaration"] (/home/pedr/repo/eslint-plugin-prefer-arrow/node_modules/eslint-plugin-prefer-arrow-functions/dist/prefer-arrow-functions.js:241:29)
    at /home/pedr/repo/eslint-plugin-prefer-arrow/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Allow functions with certain names

Description

In Angular, factories should be named functions, as you can read here angular/angular#13702 and here angular/angular#13614. Because of that, this rule interferes and throws when a factory is needed to be used.

@NgModule({
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory(httpLink: HttpLink): ApolloClientOptions<any> { // <-- Throws
        return {
          link: httpLink.create({ uri }),
          cache: new InMemoryCache(),
        };
      },
      deps: [HttpLink],
    },
  ],
})
export class GraphQLModule {}
export function createApollo(httpLink: HttpLink): ApolloClientOptions<any> { // <--- Also throws
  return {
    link: httpLink.create({ uri }),
    cache: new InMemoryCache(),
  };
}

Suggested Solution

Adding an option that allows us to add patterns to ignore would be helpful because then we would only need to come up with a standard name for factories in the project.

Help Needed

Ignore generator functions

There is no arrow syntax for generator functions, however an error is thrown when a generator function is found. This rule should be ignored on generator functions.

Removes comments and formatting

Description

Input code:

function someFn(
	// comment a
	a,
    // comment b
    b,
) {}

Fixed code:

const someFn = (a, b) => {};

Suggested Solution

Preserve whitespace and comments

Help Needed

Option to only allow named function *expressions*, not declarations

Description

Many libraries require named functions for various things, but almost all of them end up taking those functions as expressions, rather than requiring them to be declarations. For instance, React's forwardRef works best with a named function rather than an arrow function, because React will use the name for things like debugging information. But that function is an expression passed to forwardRef(); it isn't usually (and never has to be) a function declaration which binds the function to a variable in scope. That's the thing our team actually wants to avoid. We want to always use const to declare variables, never function; and we never want to use anonymous non-arrow function expressions; but we sometimes need to use named function expressions to work well with certain libraries.

Suggested Solution

An option such that this code is correct:

# Arrow function
const doSomething = () => {
  console.log('Doing something!');
};

# Named function expression
useThisFunction(function doSomething() {
  console.log('Doing something!');
});

while this code is incorrect:

# Named function declaration
function doSomething() {
  console.log('Doing something!');
}

# Anonymous (non-arrow) function expression
useThisFunction(doSomething() {
  console.log('Doing something!');
});

Perhaps allowNamedFunctions: "only-expressions"?

Help Needed

I may be able to work on this if it would be accepted.

Fix loses generic

Description

Given

function identity<T>(t: T): T { return t; }

when we run the fix we get this:

const identity = (t: T) => t;

I expected to get this:

const identity = <T>(t: T) => t;

Suggested Solution

Help Needed

Generic on TSX (React Component) gets incorrectly converted

Description

This plugin incorrectly fixes the generics syntax for React components with a single type parameter (<T>).

For example: if you open a TypeScript + React project and create a MyComponent.tsx file with the following content:

type MyComponentProps<T> = {
  data: T;
};

function MyComponent<T>({ data }: MyComponentProps<T>) {
  return (<div>{/* JSX content */}</div>)
};

When auto-fixing, you'll end up with:

type MyComponentProps<T> = {
  data: T;
};

const MyComponent = <T>({ data }: MyComponentProps<T>) => <div>{/* JSX content */}</div>;

This is not valid syntax, given that <T> in TSX is interpreted as an opening tag. To fix this, users must manually add a trailing comma to the type argument T, transforming it into <T,>.

Recording.2024-01-21.151114.mp4

Suggested Solution

Automatically add the trailing comma if the error is being fixed on a .tsx file.

Help Needed

I can try to work on this if we get #25 and #26 going, don't want to stack too many requests ๐Ÿ˜…

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.