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

[New] import/order: add support for named imports #3043

Merged
merged 1 commit into from
Sep 9, 2024

Conversation

manuth
Copy link
Contributor

@manuth manuth commented Sep 1, 2024

import/order: add support for named imports

Changes made in this PR change the import/order rule to allow configuring the order of named specifiers in import, export and require statements.

This will report errors and automatically fix expressions as shown in this example:
Reports error:

import { Bravo, Alpha } from 'foo';
const { Delta, Charlie } = require('foo');
export { Foxtrot, Echo } from 'foo';
export { Alpha as Hotel, India, Alpha as Golf };

Fixed code:

import { Alpha, Bravo } from 'foo';
const { Charlie, Delta } = require('foo');
export { Echo, Foxtrot } from 'foo';
export { Alpha as Golf, Alpha as Hotel, India } from 'foo';

This feature heavily uses the pre-existing functions used for re-ordering import/export statements and thus does not require a lot of changes.

To address the requirement brought forward by @ronparkdev, there are 3 options named.import, named.export and named.require for individually forcing ordering of named items for the specified category.

Furthermore, in response to the comment written by @JensDll, there is an option types which allows to specify the order of the specifiers based on their category:

  • mixed: all specifiers are ordered alphabetically
  • types-first: type imports must occur first
  • types-last: value imports must occur first

With this option, one could force type imports to occur last by setting the options of the order rule to the following:

{
  "named": {
    "enabled": true,
    "types": "types-last"
  },
  "alphabetize": { "order": "asc" }
}

Things to consider

  • Following tiny bit of code makes use of RegExp:
    const gapCode = sourceCode.text.substring(firstRootEnd, secondRootStart).replace(/,$/, '');

    const gapCode = sourceCode.text.substring(secondRootEnd, firstRootStart).replace(/^,/, '');
  • The lines between the default and the type/value groups are a little blurred as a default re-export technically still is either a value or a type export. default will take highest priority which means that both export { type default as Readline } from 'foo' and export { default as Readline } from 'foo' will have their group set to default.
  • named specifiers are not only sorted by their source name, but also by their alias
  • When two specifiers have the same source name (like, say, const { Alpha: Bravo, Alpha } = require('foo');), error messages will contain both the original name and the alilas for preventing confusion:
    `Alpha` import should occur before import of `Alpha as Bravo`
  • For enabling forced ordering for all kinds of expressions, the named or the named.enabled option can be set to true. However, named.all might be a more suitable option name (?)

Related

Merging this PR will fix #2553 and fix #1787

Copy link

codecov bot commented Sep 1, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 95.46%. Comparing base (a9018a8) to head (95849c8).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3043      +/-   ##
==========================================
+ Coverage   95.31%   95.46%   +0.14%     
==========================================
  Files          82       82              
  Lines        3438     3549     +111     
  Branches     1186     1244      +58     
==========================================
+ Hits         3277     3388     +111     
  Misses        161      161              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@ljharb ljharb left a comment

Choose a reason for hiding this comment

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

There's a number of lines not covered by tests (see the annotations in the diff tab)

docs/rules/order.md Outdated Show resolved Hide resolved
docs/rules/order.md Outdated Show resolved Hide resolved
src/rules/order.js Outdated Show resolved Hide resolved
src/rules/order.js Outdated Show resolved Hide resolved
src/rules/order.js Outdated Show resolved Hide resolved
src/rules/order.js Outdated Show resolved Hide resolved
src/rules/order.js Outdated Show resolved Hide resolved
src/rules/order.js Outdated Show resolved Hide resolved
src/rules/order.js Outdated Show resolved Hide resolved
src/rules/order.js Outdated Show resolved Hide resolved
@ljharb ljharb marked this pull request as draft September 1, 2024 21:31
@manuth manuth force-pushed the named-imports branch 2 times, most recently from 5d0b93a to 9a43a2d Compare September 3, 2024 01:20
@manuth
Copy link
Contributor Author

manuth commented Sep 4, 2024

Alright! I guess I'm ready
What can I do about the tests of package versions seemingly unable to detect type exports?

@manuth manuth marked this pull request as ready for review September 4, 2024 17:58
@ljharb
Copy link
Member

ljharb commented Sep 4, 2024

I'll take a look at whatever tests fail.

@manuth
Copy link
Contributor Author

manuth commented Sep 6, 2024

I had to switch to draft for an instant here, because I have noticed that the named ordering did not work if they are spreaded across multiple lines.

I was able to fix this now - thus switching back to Ready for review

@manuth manuth marked this pull request as ready for review September 6, 2024 14:48
@ljharb
Copy link
Member

ljharb commented Sep 6, 2024

@manuth any reason for the custom trimEnd function instead of the standard one?

@manuth
Copy link
Contributor Author

manuth commented Sep 6, 2024

The trimEnd function doesn't seem to exist in older Node.js versions.

@ljharb
Copy link
Member

ljharb commented Sep 6, 2024

That's what the string.prototype.trimend package is for.

@manuth
Copy link
Contributor Author

manuth commented Sep 6, 2024

Ooh weird - I felt like the checks once didn't run through cause of it
Maybe I'm mistaken

I'll try to change it back, then! Thanks 😄

@ljharb
Copy link
Member

ljharb commented Sep 6, 2024

oh no, what i mean is, add that package as a dependency and import it instead of rolling your own

Copy link

socket-security bot commented Sep 6, 2024

🚨 Potential security issues detected. Learn more about Socket for GitHub ↗︎

To accept the risk, merge this PR and you will not be notified again.

Alert Package NoteSourceCI
Critical CVE npm/babel-traverse@6.26.0 ⚠︎

View full report↗︎

Next steps

What is a critical CVE?

Contains a Critical Common Vulnerability and Exposure (CVE).

Remove or replace dependencies that include known critical CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Take a deeper look at the dependency

Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support [AT] socket [DOT] dev.

Remove the package

If you happen to install a dependency that Socket reports as Known Malware you should immediately remove it and select a different dependency. For other alert types, you may may wish to investigate alternative packages or consider if there are other ways to mitigate the specific risk posed by the dependency.

Mark a package as acceptable risk

To ignore an alert, reply with a comment starting with @SocketSecurity ignore followed by a space separated list of ecosystem/package-name@version specifiers. e.g. @SocketSecurity ignore npm/foo@1.0.0 or ignore all packages with @SocketSecurity ignore-all

  • @SocketSecurity ignore npm/babel-traverse@6.26.0

@ljharb
Copy link
Member

ljharb commented Sep 6, 2024

k, i've rebased this and i think it's ready to land, but i'm going to wait til i get a patch release out first.

@manuth
Copy link
Contributor Author

manuth commented Sep 6, 2024

Awesome, thank you so much 😄
Looking forward to it!

@manuth
Copy link
Contributor Author

manuth commented Sep 6, 2024

Just saw a little inelegance in the JSON schema I have written
Will force push the change

@ljharb ljharb merged commit 95849c8 into import-js:main Sep 9, 2024
309 of 310 checks passed
renovate bot added a commit to andrei-picus-tink/auto-renovate that referenced this pull request Oct 4, 2024
| datasource | package              | from   | to     |
| ---------- | -------------------- | ------ | ------ |
| npm        | eslint-plugin-import | 2.30.0 | 2.31.0 |


## [v2.31.0](https://github.com/import-js/eslint-plugin-import/blob/HEAD/CHANGELOG.md#2310---2024-10-03)

##### Added

-   support eslint v9 (\[[#2996](import-js/eslint-plugin-import#2996)], thanks \[[@G-Rath](https://github.com/G-Rath)] \[[@michaelfaith](https://github.com/michaelfaith)])
-   \[`order`]: allow validating named imports (\[[#3043](import-js/eslint-plugin-import#3043)], thanks \[[@manuth](https://github.com/manuth)])
-   \[`extensions`]: add the `checkTypeImports` option (\[[#2817](import-js/eslint-plugin-import#2817)], thanks \[[@phryneas](https://github.com/phryneas)])

##### Fixed

-   `ExportMap` / flat config: include `languageOptions` in context (\[[#3052](import-js/eslint-plugin-import#3052)], thanks \[[@michaelfaith](https://github.com/michaelfaith)])
-   \[`no-named-as-default`]: Allow using an identifier if the export is both a named and a default export (\[[#3032](import-js/eslint-plugin-import#3032)], thanks \[[@akwodkiewicz](https://github.com/akwodkiewicz)])
-   \[`export`]: False positive for exported overloaded functions in TS (\[[#3065](import-js/eslint-plugin-import#3065)], thanks \[[@liuxingbaoyu](https://github.com/liuxingbaoyu)])
-   `exportMap`: export map cache is tainted by unreliable parse results (\[[#3062](import-js/eslint-plugin-import#3062)], thanks \[[@michaelfaith](https://github.com/michaelfaith)])
-   `exportMap`: improve cacheKey when using flat config (\[[#3072](import-js/eslint-plugin-import#3072)], thanks \[[@michaelfaith](https://github.com/michaelfaith)])
-   adjust "is source type module" checks for flat config (\[[#2996](import-js/eslint-plugin-import#2996)], thanks \[[@G-Rath](https://github.com/G-Rath)])

##### Changed

-   \[Docs] \[`no-relative-packages`]: fix typo (\[[#3066](import-js/eslint-plugin-import#3066)], thanks \[[@joshuaobrien](https://github.com/joshuaobrien)])
-   \[Performance] \[`no-cycle`]: dont scc for each linted file (\[[#3068](import-js/eslint-plugin-import#3068)], thanks \[[@soryy708](https://github.com/soryy708)])
-   \[Docs] \[`no-cycle`]: add `disableScc` to docs (\[[#3070](import-js/eslint-plugin-import#3070)], thanks \[[@soryy708](https://github.com/soryy708)])
-   \[Tests] use re-exported `RuleTester` (\[[#3071](import-js/eslint-plugin-import#3071)], thanks \[[@G-Rath](https://github.com/G-Rath)])
-   \[Docs] \[`no-restricted-paths`]: fix grammar (\[[#3073](import-js/eslint-plugin-import#3073)], thanks \[[@unbeauvoyage](https://github.com/unbeauvoyage)])
-   \[Tests] \[`no-default-export`], \[`no-named-export`]:  add test case (thanks \[[@G-Rath](https://github.com/G-Rath)])
renovate bot added a commit to andrei-picus-tink/auto-renovate that referenced this pull request Oct 4, 2024
| datasource | package              | from   | to     |
| ---------- | -------------------- | ------ | ------ |
| npm        | eslint-plugin-import | 2.30.0 | 2.31.0 |


## [v2.31.0](https://github.com/import-js/eslint-plugin-import/blob/HEAD/CHANGELOG.md#2310---2024-10-03)

##### Added

-   support eslint v9 (\[[#2996](import-js/eslint-plugin-import#2996)], thanks \[[@G-Rath](https://github.com/G-Rath)] \[[@michaelfaith](https://github.com/michaelfaith)])
-   \[`order`]: allow validating named imports (\[[#3043](import-js/eslint-plugin-import#3043)], thanks \[[@manuth](https://github.com/manuth)])
-   \[`extensions`]: add the `checkTypeImports` option (\[[#2817](import-js/eslint-plugin-import#2817)], thanks \[[@phryneas](https://github.com/phryneas)])

##### Fixed

-   `ExportMap` / flat config: include `languageOptions` in context (\[[#3052](import-js/eslint-plugin-import#3052)], thanks \[[@michaelfaith](https://github.com/michaelfaith)])
-   \[`no-named-as-default`]: Allow using an identifier if the export is both a named and a default export (\[[#3032](import-js/eslint-plugin-import#3032)], thanks \[[@akwodkiewicz](https://github.com/akwodkiewicz)])
-   \[`export`]: False positive for exported overloaded functions in TS (\[[#3065](import-js/eslint-plugin-import#3065)], thanks \[[@liuxingbaoyu](https://github.com/liuxingbaoyu)])
-   `exportMap`: export map cache is tainted by unreliable parse results (\[[#3062](import-js/eslint-plugin-import#3062)], thanks \[[@michaelfaith](https://github.com/michaelfaith)])
-   `exportMap`: improve cacheKey when using flat config (\[[#3072](import-js/eslint-plugin-import#3072)], thanks \[[@michaelfaith](https://github.com/michaelfaith)])
-   adjust "is source type module" checks for flat config (\[[#2996](import-js/eslint-plugin-import#2996)], thanks \[[@G-Rath](https://github.com/G-Rath)])

##### Changed

-   \[Docs] \[`no-relative-packages`]: fix typo (\[[#3066](import-js/eslint-plugin-import#3066)], thanks \[[@joshuaobrien](https://github.com/joshuaobrien)])
-   \[Performance] \[`no-cycle`]: dont scc for each linted file (\[[#3068](import-js/eslint-plugin-import#3068)], thanks \[[@soryy708](https://github.com/soryy708)])
-   \[Docs] \[`no-cycle`]: add `disableScc` to docs (\[[#3070](import-js/eslint-plugin-import#3070)], thanks \[[@soryy708](https://github.com/soryy708)])
-   \[Tests] use re-exported `RuleTester` (\[[#3071](import-js/eslint-plugin-import#3071)], thanks \[[@G-Rath](https://github.com/G-Rath)])
-   \[Docs] \[`no-restricted-paths`]: fix grammar (\[[#3073](import-js/eslint-plugin-import#3073)], thanks \[[@unbeauvoyage](https://github.com/unbeauvoyage)])
-   \[Tests] \[`no-default-export`], \[`no-named-export`]:  add test case (thanks \[[@G-Rath](https://github.com/G-Rath)])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
2 participants