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 custom linting rules #4132

Merged
merged 9 commits into from
Jul 10, 2023
Merged

Conversation

lhemerly
Copy link
Contributor

@lhemerly lhemerly commented Mar 22, 2023

Fixes #3919

Adds a custom plugin for Solhint that implements the project's Solidity guidelines.

@changeset-bot

This comment was marked as off-topic.

@frangio
Copy link
Contributor

frangio commented Mar 22, 2023

Nice @lhemerly! This is appreciated.

Is it possible to have the "plugin" as a JS file in this repository, rather than a separate npm package? I would like to do that as it will be easier for us to maintain and evolve.

@lhemerly
Copy link
Contributor Author

lhemerly commented Mar 23, 2023

As far as I know it is not possible right now as you can't set-up the plugin path in solhint:
Solhint - Issue#206

It is hardcoded to look up for solhint-plugin-${pluginName} in the node_modules folder:
Solhint loadPlugin Function

I may try a PR on Solhint for custom plugins paths later

Fixes OpenZeppelin#3919

Add solhint-plugin-ozcontracts to devDependencies
Add ozonctracts to .solhint.json plugins
Add oz-contracts-custom to .solhint.json rules

#### PR Checklist

- [ x] Tests
- [ ] Documentation
- [ ] Changeset entry (run `npx changeset add`)
@lhemerly
Copy link
Contributor Author

Just a follow up, PR in solhint created:
Solhint PR for Issue #206

@frangio
Copy link
Contributor

frangio commented Mar 24, 2023

Maybe we could make it work by defining the package locally in the repo? Not exactly but sort of monorepo style.

@lhemerly
Copy link
Contributor Author

The way I can imagine making it work as solhint is right now is to take the "solhint-plugin-ozcontracts" folder inside node_modules out of the gitignore and work with the .js file there as part of the repo. The way npm (or yarn) install works it won't change that folder as long as we remove and keep it out of package.json.

If you think it is ok to go with that I can make the necessary changes

@frangio
Copy link
Contributor

frangio commented Jun 16, 2023

Putting in node_modules is not ideal. We should be able to put it in a subdirectory somewhere in the repo and add "solhint-plugin-custom": "file:./solhint-plugin" in the dependencies.

@frangio
Copy link
Contributor

frangio commented Jul 6, 2023

@lhemerly I've vendored your plugin into this repository like I suggested.

This should be a great start to begin to build more custom linting rules. Thanks!

@frangio frangio requested review from Amxx and ernestognw July 6, 2023 03:18
@frangio
Copy link
Contributor

frangio commented Jul 6, 2023

@Amxx @ernestognw Note that this will allow us to have internal constants without leading underscore moving forward.

}
},

// TODO: re-enable and fix
Copy link
Contributor

Choose a reason for hiding this comment

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

We have some code that causes this rule to fail so I'm proposing to merge and enable it later.

Co-authored-by: Hadrien Croubois <[email protected]>
if (!/^_/.test(node.name)) {
this.error(node, 'Private variables must be prefixed with underscore');
}
}
Copy link
Collaborator

@Amxx Amxx Jul 6, 2023

Choose a reason for hiding this comment

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

Should we also have some rule that if the stateVar is constantOrImmutable, then it must NOT start with an underscore ? or do we accept both ?

Suggested change
}
} else if (node.isStateVar && constantOrImmutable) {
if (/^_/.test(node.name)) {
this.error(node, 'Constant and immutable variables should not be prefixed with underscore');
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, but this causes the rule to fail in a few places.

I added the rule but commented it out, and I'd propose to do another PR next week fixing those things. Does this sound ok?

Copy link
Collaborator

Choose a reason for hiding this comment

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

So we will have 2 follow up PRs that :

  • enable the rule
  • fix the code
    ?

That sounds ok

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah or just one PR doing the two.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe the rule should also check that the name is capitalized.

Copy link
Contributor

Choose a reason for hiding this comment

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

That should be already handled by the casing rules in solhint.config.js, specifically const-name-snakecase.

@lhemerly
Copy link
Contributor Author

lhemerly commented Jul 6, 2023

Just an update, development branch in solhint adjusted plugins to be in any path:
protofire/solhint#424 (comment)


module.exports = {
plugins: ['openzeppelin'],
rules: Object.fromEntries(rules.map(r => [r, 'error'])),
Copy link
Member

Choose a reason for hiding this comment

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

Why not define it like an object?

const rules = {
  'no-unused-vars': 'error',
  ...
}

Not a blocker because everything shows an "error", I just wanted to point out that the array doesn't seem to be needed

Copy link
Contributor

@frangio frangio Jul 10, 2023

Choose a reason for hiding this comment

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

We need to use fromEntries in some way because we get the names of the custom rules dynamically:

customRules.map(r => `openzeppelin/${r.ruleId}`)

The rest could be an object, but I had a feeling that this was clearer? Let me know if it's too confusing.

@frangio frangio merged commit cd981f6 into OpenZeppelin:master Jul 10, 2023
@gitpoap-bot
Copy link

gitpoap-bot bot commented Jul 10, 2023

Congrats, your important contribution to this open-source project has earned you a GitPOAP!

GitPOAP: 2023 OpenZeppelin Contracts Contributor:

GitPOAP: 2023 OpenZeppelin Contracts Contributor GitPOAP Badge

Head to gitpoap.io & connect your GitHub account to mint!

Learn more about GitPOAPs here.

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

Successfully merging this pull request may close these issues.

Create custom linting rules for conventions
4 participants