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

[import/order] sort order within groups #389

Closed
nevir opened this issue Jun 21, 2016 · 40 comments · Fixed by #629
Closed

[import/order] sort order within groups #389

nevir opened this issue Jun 21, 2016 · 40 comments · Fixed by #629

Comments

@nevir
Copy link
Contributor

nevir commented Jun 21, 2016

It'd be handy if import/order either played nice with eslint's sort-imports rule (if that's feasible?) - or implemented something along the same lines, but on a per-group basis

@benmosher
Copy link
Member

Can you provide an example of what you want that isn't working?

@nevir
Copy link
Contributor Author

nevir commented Jun 21, 2016

Yeah, sorry, say for example you have the following files:

a.js
c.js
subdir/
  b.js
  d.js
  index.js

index.js has the following:

import a from '../a';
import c from '../c';

import b from './b';
import d from './d';

And eslint is configured with:

import/order: [2, {groups: ['parent', 'sibling'], newlines-between: 'always'}]
sort-imports: 2

When running eslint on subdir/index.js, you receive an Imports should be sorted alphabetically error on the import b from '.b/'; line.

(e.g sort-imports is checking the imports regardless of groups, but really we need inner-group sorting)

@jfmengels
Copy link
Collaborator

I like the idea, but I'm worried that we'd get a lot of requests to support plenty of types to order the imports.

I know of a few that are requested already

  • Alphabetically, by import name
  • By length of the line (to have a stair-case like code)

I could very well see an alphabetical order too, but by the name of the variable it will be affected to (not sure how that'd work with destructuring), which makes more sense IMO as that makes looking for a variable declaration easier.

Don't know if people will want other types of sort, but I think we could be surprised.

We'd probably need support for exceptions too (personally, I always like to have lodash as the first import in my files. Don't ask me why). Like when using a test runner like tape/ava, "I want that to always be the first import", would make sense I think.

Maybe I'm overthinking it, but this seems like potentially quite a lot of work to maintain. That said, if we're willing to commit to this work and/or accept only much requested sort options, I'm all for it.

@benmosher
Copy link
Member

+1 to @jfmengels on this being a lot of work.

The simplest thing I can imagine doing would be to allow a group-sort comparator function to be configured as a rule option. Such a function would take the two ImportDeclaration nodes to compare, and would be on its own from there.

Then the community could support modules or shared configs with comparators that folks like.

In the event that one rose to the top, we could integrate it (but the beauty would be: we don't need to).

I would accept a PR implementing such a comparator option for this rule, pending @jfmengels' consideration.

@jfmengels
Copy link
Collaborator

Such a function would take the two ImportDeclaration nodes to compare

ImportDeclaration or require calls. That's not sufficient, if you want to compare the line length for instance. Or maybe it is but then you'd have to go play witht the parent field, make assumptions. Sounds tricky, but possible. Not sure how/what else we could send to the comparator without sending the whole file 😕

I like the module idea (even though it sounds a bit overcomplicated/tedious for what it is).
Do we agree that it would look something like (I chose sort but we could rename that later):
"import/order": ["error", {"groups": [...], "sort": ["sorter-module-1", "sorter-module-2"]}]
and we'd go and import sorter-module-1, call it with whatever data we would like to send it, then sort the items with the same sort with sorter-module-2.

This way, if we chose to integrate one or a few into the project, we could, simply by first looking for it in the "internal modules", then in external modules.

I'd be fine with this too. We'll have to figure out what data to send to the comparator to at least sort in every way I mentioned in my previous comment.

@benmosher
Copy link
Member

benmosher commented Jun 30, 2016

we'd go and import sorter-module-1, call it with whatever data we would like to send it, then sort the items with the same sort with sorter-module-2.

I was thinking it would be mandatory to use JS config, and the config file itself would be responsible for require-ing (or implementing) the sort comparator. But this would also work.

@jfmengels
Copy link
Collaborator

Huh, didn't even know that was possible, and that you could pass non-JSON values like functions.

If we'd go and require it, would that cause problems depending on what npm version you'd use (nested module structure in npm 2 vs flat module structure in npm 3)?

I think it'd be a shame to force the whole config to be a JS file just because of this option (if option is used) if we can avoid it, though it would be a simpler solution.

We could start implementing first using a JS only solution using a function as param, and when we're happy with how it's working, accept a string and require a module.

@benmosher
Copy link
Member

I think it'd be a shame to force the whole config to be a JS file just because of this option (if option is used) if we can avoid it, though it would be a simpler solution.

I think of it sortof opposite: it's fantastic that the option is there to use pure JS config, for esoteric options like this.

I'm making an unfounded assumption that this is not an option that will see frequent use. That said, since some strategy will potentially find dominance, the if (typeof sorter === 'string') sorter = require(sorter) strategy feels right (and if nothing else, easy).

@jfmengels
Copy link
Collaborator

jfmengels commented Jun 30, 2016

it's fantastic that the option is there to use pure JS config

Agreed, but since you can't merge a js config and a YAML/JSON config, you'd have to port your entire config file from YAML/JSON to JS just to activate this option.

I'm making an unfounded assumption that this is not an option that will see frequent use.

Hmm... I would assume the opposite (if the option is easy to use). People who use this rule already want to sort their imports, this is just one natural step further. I would personally activate it (probably the staircase rule).

Just thought of the exceptions argument I made. You'd probably want to allow settings in your comparator too, probably something like this:

{
  "import/order": ["error", {
    "groups": [
        "builtin",
        ["sibling", "parent"],
        "index",
    ],
    "newlines-between": true,
    "sort": [
        {
            "comparator": "sorter-module-1", // string or function
            "exceptions": ["lodash"] // or however you give options
        },
        {
            "comparator": "sorter-module-2",
            "reverse": true
        }
    ]
  }]
}

Man... the settings for this rule could use it's own file at this rate...

Like I said earlier: this is a rabbit hole option (and the rule even more so).

@benmosher
Copy link
Member

Yep, it could get wild.

You might almost say you could build a whole plugin for it... 😉

@benmosher
Copy link
Member

Upon reflection, I think you're right--people will probably love and use this. I am just projecting too much.

I'm happy to support however you want to come at this.

@chrisnojima
Copy link

I think a simple alphabetical inner sort would cover a lot of use cases and likely be very simple to implement (vs a super generic / powerful mechanism)

@kevinSuttle
Copy link

kevinSuttle commented Aug 9, 2016

Would this sort, and thus, extend options for ordering imports and requires?

-import Foo from 'foo'
-require('bar')
-import Baz from 'baz'
require('fizz')
\r
+import Baz from 'baz'
+import Foo from 'foo'
+require('bar')
require('fizz')
\r

@jfmengels
Copy link
Collaborator

@kevinSuttle If that's possible, that'd be awesome, but I'm not sure that's it's easy to do (if requires are all over the file).

Anyway, let's do this. I have other things I'd like to work on currently, so I won't work on this for the foreseeable future.
But I can review a PR and give some guidance, if someone feels up to it :)

@nevir
Copy link
Contributor Author

nevir commented Aug 9, 2016

@kevinSuttle AFAIK it's not valid ES to have imperative statements before import declarations. Babel and the other transpilers don't tend to enforce it, but once imports are supported natively we probably will see it enforced. That might be better as a separate rule (since it's more of a correctness thing)

(imports are processed before any code in the module is executed)

@jfmengels
Copy link
Collaborator

I thought it was valid, but that it was hoisted (like functions).
Anyway, better to imagine it is possible as it is allowed anyway with Babel.

@kevinSuttle
Copy link

Oh, I don't mean putting anything before imports. I'm asking about this rule treating require as an exception to appear immediately on the line below the last import statement. Sorry, I could have made that clearer initially.

@benmosher
Copy link
Member

@nevir: @jfmengels is right, they'll be hoisted, but it's still valid to have statements before them. Just might result in confusion. (thus, the import-first rule in this plugin 🤓)

@nevir
Copy link
Contributor Author

nevir commented Aug 10, 2016

aha! k; thanks for fixing my understanding on that 👍

randallreedjr pushed a commit to randallreedjr/eslint-plugin-import that referenced this issue Oct 17, 2016
* After sorting imports by group, allow sorting alphabetically within a group
* import/order rule now accepts sort-order option that may be 'ignore' (default) or 'alphabetical'
* Fixes import-js#389
randallreedjr pushed a commit to randallreedjr/eslint-plugin-import that referenced this issue Oct 17, 2016
* After sorting imports by group, allow sorting alphabetically within a group
* import/order rule now accepts sort-order option that may be 'ignore' (default) or 'alphabetical'
* Fixes import-js#389
randallreedjr pushed a commit to randallreedjr/eslint-plugin-import that referenced this issue Oct 17, 2016
* After sorting imports by group, allow sorting alphabetically within a group
* import/order rule now accepts sort-order option that may be 'ignore' (default) or 'alphabetical'
* Fixes import-js#389
randallreedjr pushed a commit to randallreedjr/eslint-plugin-import that referenced this issue Oct 17, 2016
* After sorting imports by group, allow sorting alphabetically within a group
* import/order rule now accepts sort-order option that may be 'ignore' (default) or 'alphabetical'
* Fixes import-js#389
randallreedjr pushed a commit to randallreedjr/eslint-plugin-import that referenced this issue Oct 18, 2016
* After sorting imports by group, allow sorting alphabetically within a group
* import/order rule now accepts sort-order option that may be 'ignore' (default) or 'alphabetical'
* Fixes import-js#389
randallreedjr pushed a commit to randallreedjr/eslint-plugin-import that referenced this issue Oct 18, 2016
* After sorting imports by group, allow sorting alphabetically within a group
* import/order rule now accepts sort-order option that may be 'ignore' (default) or 'alphabetical'
* Fixes import-js#389
@ljharb
Copy link
Member

ljharb commented Aug 2, 2017

Ah, I found #629 - that has changes requested on it, and the contributor who requested them is unavailable for personal reasons. The thing to do is "be patient" - I know it's difficult.

@ismay
Copy link

ismay commented Aug 2, 2017

This project is quite maintained; just because one PR hasn't had movement doesn't mean that it's abandoned

Oh I'm not saying this project is not maintained, just that forking it might be a way to move this forward. Which would require someone who wants to maintain the fork.

If there's anyone who wants to do that we could use the fork and maybe merge back in the future if the project owner wants to.

@ljharb
Copy link
Member

ljharb commented Aug 2, 2017

You can npm install from the git branch for the PR, if you want to test it out.

@ismay
Copy link

ismay commented Aug 3, 2017

You can npm install from the git branch for the PR, if you want to test it out.

I know.

@lydell
Copy link
Contributor

lydell commented Apr 29, 2018

As far as I can tell, the order rule works great together with https://github.com/marudor/eslint-plugin-sort-imports-es6-autofix

EDIT: But still a bit quirkily, see #389 (comment) and #389 (comment)

I now recommend eslint-plugin-simple-import-sort instead.

@benmosher
Copy link
Member

concerned parties: please see #951 and comment there if you have ideas on how to manage/govern the development of the order rule. it has definitely been languishing since @jfmengels went dark. would love to get someone passionate about it on as a collaborator to tend it.

@gdaolewe
Copy link

gdaolewe commented Jun 15, 2018

@lydell Unfortunately the autofix of https://github.com/marudor/eslint-plugin-sort-imports-es6-autofix and the order rule don't work well together. If you run a config with just the import/order rule first with "newlines-between": "always" so that the groups are separated and then run sort-imports-es6-autofix/sort-imports-es6, you will end up with first imports sorted into groups with the groups themselves in the correct order and then imports alphabetically sorted within the groups, but if you just run a config with both enabled you will end up with the groups in the correct order but no newlines between and no sorting within groups.

If you manually resolve these violations the result will pass this config, but that's a pain I'm interested in avoiding. Unfortunately I'm not aware of a way to run these rules separately in a specific order other than running eslint twice passing a different config each time, which doesn't really work in the case that you want to opt-in specific directories of your application gradually.

@lydell
Copy link
Contributor

lydell commented Jun 15, 2018

@gdaolewe Yeah, I've also noticed that problem after using both at the same time for a little while. It works OK-ish, but there are definitely (solvable) problems every now and then.

ljharb pushed a commit to randallreedjr/eslint-plugin-import that referenced this issue Jul 10, 2018
@Udokah
Copy link

Udokah commented Mar 4, 2019

What is the status of this enhancement? Has it been merged? will it be merged?

@laurenraddatz
Copy link

any update...?

@caribou-code
Copy link

Any update? Issue has been open for 3.5 years. I could have hand crafted a rare faberge egg in that time.

@ljharb
Copy link
Member

ljharb commented Nov 26, 2019

Two, even, and if you had, and sold them, and donated the funds to sponsor the project's maintainers, then it would have been much easier to set aside the time to fix it :-D

#629 and #1105 and #1360 all attempt to address this. These are on my queue to look at, and I will do so as soon as I can find the time.

@ljharb ljharb closed this as completed in 8224e51 Dec 7, 2019
marcusdarmstrong pushed a commit to marcusdarmstrong/eslint-plugin-import that referenced this issue Dec 9, 2019
…n groups

Fixes import-js#1406. Fixes import-js#389. Closes import-js#629. Closes import-js#1105. Closes import-js#1360.

Co-Authored-By: dannysindra <als478@cornell.edu>
Co-Authored-By: Radim Svoboda <radim.svoboda@socialbakers.com>
Co-Authored-By: Soma Lucz <luczsoma@gmail.com>
Co-Authored-By: Randall Reed, Jr <randallreedjr@gmail.com>
Co-Authored-By: Jordan Harband <ljharb@gmail.com>
@techsin
Copy link

techsin commented Dec 19, 2019

is it possible to sort based on variable name instead of import path within a group?

@ljharb
Copy link
Member

ljharb commented Dec 19, 2019

Variable name is just a local choice; the path is what’s meaningful.

@techsin
Copy link

techsin commented Dec 19, 2019

let's see from user's perspective.. you open a file with 500 lines and 15 imports. You are looking to see if this file uses some custom module, so path isn't gonna be like import abc from "abc";. but import abc from "../../common/homepage/services/api/auth/........."; every path can be pointing to a wildly different location and therefore have different lengths. So you'd Ignore the paths and try to quickly skim through variables names, which are highlighted better in most UI themes by default. But if they aren't organized you give up and type out the whole thing in search. (which takes longer time).

TLDR: Variable names are easier to read because they are not nested and highlighted by IDE themes by default. So sorting that has compounding advantage. It's making better option more better. I'm thankful for all the work and it's 100x better than nothing. But I'd like to suggest a way to sort based on variable names instead of path name.

@ljharb
Copy link
Member

ljharb commented Dec 19, 2019

If you have that many imports, wouldn't you want to use search anyways, since that'd always be fastest?

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

Successfully merging a pull request may close this issue.