Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add prefer-class-fields rule #2512

Open
wants to merge 29 commits into
base: main
Choose a base branch
from

Conversation

FRSgit
Copy link

@FRSgit FRSgit commented Dec 16, 2024

Adds prefer-class-fields rule which turns:

class Foo {
  constructor() {
    this.foo = 'foo';
  }
}

into:

class Foo {
  foo = 'foo';
}

Fixes #314


IssueHunt Summary

Referenced issues

This pull request has been submitted to:


@fisker
Copy link
Collaborator

fisker commented Dec 17, 2024

What should we do if the assignment is unreachable?

			class Foo {
				constructor(x) {
					if (x) {return}
					this.foo = 'foo';
				}
			}

@fregante
Copy link
Collaborator

What should we do if the assignment is unreachable?

It's dynamically set, so it cannot be statically defined. It should not be reported by this rule.

@FRSgit
Copy link
Author

FRSgit commented Dec 20, 2024

Hey @fregante!
Thanks for your input about the linting - is there a ruleset somewhere which I could use? The lint task in this repo is not doing this much (at least for me) and it removes some of your changes 😄 E.g. it seems that the part /** @type {import('eslint').Rule.RuleModule} */ is required by the lint task - after your change it was failing with:
image
So, I've reverted this one change.

Or maybe we can just agree that once the work in this PR is done you'll maybe just run your linter on it once?

@FRSgit FRSgit force-pushed the feat/add-prefer-class-fields branch from 06d643a to 3a9c5f8 Compare December 20, 2024 02:02
@FRSgit
Copy link
Author

FRSgit commented Dec 22, 2024

Handled stopping of the static analysis on unsupported case: 3376845

@FRSgit FRSgit force-pushed the feat/add-prefer-class-fields branch from d907827 to 77f4954 Compare December 26, 2024 00:37
@FRSgit
Copy link
Author

FRSgit commented Dec 26, 2024

Okay, I fixed all test/linting errors connected with my rule - should I fix other as well? They seems to be connected with some default options missing in already existing rules?
cc: @sindresorhus @fregante @fisker

@FRSgit FRSgit force-pushed the feat/add-prefer-class-fields branch 2 times, most recently from 275195a to 77f4954 Compare January 16, 2025 01:29
@FRSgit
Copy link
Author

FRSgit commented Jan 16, 2025

Hey! I've merged last changes from main to the branch of this PR - now it's ready to be reviewed again

@sindresorhus
Copy link
Owner

Change the test file extension from .mjs to .js.

@FRSgit
Copy link
Author

FRSgit commented Jan 21, 2025

@sindresorhus done: 8358a43

I'm not sure yet why the tests are failing - locally they're working just fine.

@FRSgit FRSgit force-pushed the feat/add-prefer-class-fields branch from c7632d9 to 8358a43 Compare January 21, 2025 01:33
@FRSgit FRSgit force-pushed the feat/add-prefer-class-fields branch from fa07ec0 to ca160be Compare January 28, 2025 23:49
@FRSgit FRSgit requested a review from sindresorhus January 29, 2025 00:30
@FRSgit
Copy link
Author

FRSgit commented Jan 29, 2025

Okay, got it working and all of the requested changes are applied.

BTW it's weird, but for me the npm run fix:eslint-docs script worked only on node@22.
Maybe it would be good to add an .nvmrc file to the root of the repo with the node version that should be used when running npm scripts?

@FRSgit FRSgit requested a review from fisker January 31, 2025 09:22
@FRSgit
Copy link
Author

FRSgit commented Feb 15, 2025

ready to be re-reviewed @fisker

@FRSgit FRSgit force-pushed the feat/add-prefer-class-fields branch from 317cd49 to 9898da3 Compare February 15, 2025 18:05
Comment on lines +102 to +106
const constructor = classBody.body.find(x => x.kind === 'constructor');

if (!constructor || constructor.type !== 'MethodDefinition') {
return;
}
Copy link
Collaborator

@fisker fisker Feb 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

			const constructor = classBody.body.find(node => node.kind === 'constructor' && node.type !== 'MethodDefinition');

			if (!constructor) {
				return;
			}

Does TypeScript allow multiple constructor? If so, it will find the correct constructor

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typescript allows multiple constructor declarations (overloads) but only one definition (implementation). See an example here

But I don't think I understand what do you mean here - can you elaborate a bit more?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example from your link

class Box {
    public x: number;
    public y: number;
    public height: number;
    public width: number;

    constructor();                   // <- Your version will give up when find this
    constructor(obj: IBox); 
    constructor(obj?: IBox) {        // <- My version can locate this
        this.x = obj?.x ?? 0;
        this.y = obj?.y ?? 0;
        this.height = obj?.height ?? 0;
        this.width = obj?.width ?? 0;
    }   
}

Sorry, my version has a typo

-			const constructor = classBody.body.find(node => node.kind === 'constructor' && node.type !== 'MethodDefinition');
+			const constructor = classBody.body.find(node => node.kind === 'constructor' && node.type === 'MethodDefinition');

			if (!constructor) {
				return;
			}

Comment on lines +117 to +120
const validConstructorProperties
= firstInvalidProperty === -1
? constructorBody
: constructorBody.slice(0, firstInvalidProperty);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already use a loop, we can use the index directly, no need slice here.

/**
@param {import('eslint').Rule.RuleFixer} fixer
*/
* suggest(fixer) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest should be an array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rule proposal: prefer-class-fields
4 participants