-
Notifications
You must be signed in to change notification settings - Fork 161
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
Feature request: rule for ordering imports topologically and alphabetically #571
Comments
thanks @PaulRBerg for posting |
Can we sponsor you with a bounty to work on this, @dbale-altoros? feel free to share your Ethereum address on Telegram. |
Hi @PaulRBerg i'm on vacations. I'll contact you this friday o next monday |
@PaulRBerg Import parts of a file
Import parts and define alias
Import the whole file
Regarding the hierarchy
take into account there are paths like this |
thank you @dbale-altoros adding @smol-ninja and @andreivladbrg for help here |
Hi @dbale-altoros, thank you for working on this. This will save us a significant amount of time. Here are the answers to your questions:
import './../../../../token/interfaces/AFakeContract1.sol';
import '../../../../token/interfaces/FakeContract1.sol';
import { FakeContract2 } from '../../../token/interfaces/FakeContract2.sol';
import { FakeContract3 } from '../../../token/interfaces/FakeContract3.sol';
import { holaquetal, IXTokenFactory } from '../../token/interfaces/IXTokenFactory.sol';
import './../token/interfaces/IXTokenWrapper.sol';
import { IXTokenWrapper2 } from '../token/interfaces/IXTokenWrapper2.sol';
import { Afool1 } from './Afool1.sol';
import { add as func, Point, Unauthorized } from "./Foo.sol";
import { Initializable } from './openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import "./Ownable.sol";
import './ThisIsAVeryLongFileOnPurposeToTestTheFirstPathShorterThanTheLastOnelooooooooooong.sol';
import { ReentrancyGuardUpgradeable2 } from '@apenzeppelin/ReentrancyGuardUpgradeable2.sol';
import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
import "http://github.com/owner/repo/blob/branch/path/to/Contract2.sol";
import "https://github.com/owner/repo/blob/branch/path/to/Contract.sol"; Note that I have put two spaces inside the braces |
@smol-ninja thanks for the feedback |
Thanks @dbale-altoros for the update.
True and that's why we use |
oh jajaja i will steal that... never looked that up , so i left that as is |
@smol-ninja import { ReentrancyGuardUpgradeable2 } from '@apenzeppelin/ReentrancyGuardUpgradeable2.sol'; |
Its because |
@smol-ninja so for this
zContract path will be first and for this
zContract path will be first and for this
zContract path will be first but for this
aContract path will be first is that right ? |
Yes. And yes yes yes to all your questions. You are absolutely right. That's how we like to do it. |
@smol-ninja @PaulRBerg You can test it, if you clone the repo and execute Just make a file called
And of course replace I can put together a new version next week, if you can give me some feedback, that will be awesome |
Incredible. I just gave it go and realised that I made a mistake in my suggestion. I'd place the external imports above the relative imports and separate them with a "newline" to improve readability. So, the following will be placed at the top. import { ReentrancyGuardUpgradeable2 } from '@apenzeppelin/ReentrancyGuardUpgradeable2.sol';
import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
import "http://github.com/owner/repo/blob/branch/path/to/Contract2.sol";
import "https://github.com/owner/repo/blob/branch/path/to/Contract.sol"; The updated order would look like: import { ReentrancyGuardUpgradeable2 } from '@apenzeppelin/ReentrancyGuardUpgradeable2.sol';
import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
import "http://github.com/owner/repo/blob/branch/path/to/Contract2.sol";
import "https://github.com/owner/repo/blob/branch/path/to/Contract.sol";
import './../../../../token/interfaces/AFakeContract1.sol';
import '../../../../token/interfaces/FakeContract1.sol';
import { FakeContract2 } from '../../../token/interfaces/FakeContract2.sol';
import { FakeContract3 } from '../../../token/interfaces/FakeContract3.sol';
import { holaquetal, IXTokenFactory } from '../../token/interfaces/IXTokenFactory.sol';
import './../token/interfaces/IXTokenWrapper.sol';
import { IXTokenWrapper2 } from '../token/interfaces/IXTokenWrapper2.sol';
import { Afool1 } from './Afool1.sol';
import { add as func, Point, Unauthorized } from "./Foo.sol";
import { Initializable } from './openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import "./Ownable.sol";
import './ThisIsAVeryLongFileOnPurposeToTestTheFirstPathShorterThanTheLastOnelooooooooooong.sol'; The objective is to separate external imports from the relative imports. Sorry for making this mistake and increasing your work load. Does it require a major refactor in your PR? Otherwise, I tested it locally, and very happy to confirm that everything is working perfect. |
cool @smol-ninja |
@smol-ninja please try it now... |
Fantastic! I just gave it a go and it works. Don't worry about the new line, it doesn't matter much since can easily be added manually. Thank you so much @dbale-altoros for doing this. |
Thank you very much @dbale-altoros! |
@PaulRBerg @smol-ninja i guess following days i will release a new version including this rule |
new release with this feature launched |
Brilliant. Have a lovely weekend. |
Hi @dbale-altoros, I was testing the new rule and seems like there is a bug. It leads to the following sorting: import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { PRBMathUtils } from "@prb/math/test/utils/Utils.sol";
import { Constants } from "./Constants.sol";
import { CommonBase } from "forge-std/src/Base.sol";
import { SafeCastLib } from "solady/src/utils/SafeCastLib.sol";
import { Helpers } from "src/libraries/Helpers.sol"; We discussed that it would be a good idea to have external imports above the relative imports. It seems like the relative import, i.e. |
Hi' @smol-ninja , thanks for the feedback And how do yo want that to be ordered ? please specify... Relative Imports Direct Imports Is this what you mean ? I will leave the code for testing before releasing new version, like I did before. Thanks |
Yes.
I'd order the above example as the following: import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { PRBMathUtils } from "@prb/math/test/utils/Utils.sol";
import { CommonBase } from "forge-std/src/Base.sol";
import { SafeCastLib } from "solady/src/utils/SafeCastLib.sol";
import { Helpers } from "src/libraries/Helpers.sol";
import { Constants } from "./Constants.sol"; Let me know if you have any more questions. |
@smol-ninja @PaulRBerg You can test it, if you clone the repo and go to that branch and execute Just make a file called imports-order.json
And of course replace FooImports.sol with the contract of your choice I can put together a new version whenever you give me the ok on this one |
Hi @dbale-altoros, I have just tested the new PR and it looks good. Looking forward to the patch release. Thank you. |
Resolved |
Hey @dbale-altoros, thank you so much for implementing this. Tiny request: would it be possible to use double quotes instead of single quotes for the import paths? I gather that this is an opinionated choice, but:
The current behavior is problematic for us because we need to run |
@PaulRBerg sorry |
Thanks for this rule @dbale-altoros ! I've updated to the latest version and used the For example, |
@PierrickGT is this something that breaks the contracts ? or make a compilation error ? |
It compiles properly but seems a bit redundant. |
@PierrickGT feel free to push a pr for this cheers! |
It would be helpful if Solhint offered a rule for ordering imports topologically and alphabetically.
Rationale: this is a non-opinionated code design that lessens the cognitive load on users.
Example of PR where we manually ordered the imports: sablier-labs/v2-periphery#301
I propose the following logic:
../../
comes before../
, which comes before./
, which comes before./foo
./bar
comes before./foo
The text was updated successfully, but these errors were encountered: