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

fix(sort-collections): avoid sorting exports by default #918

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

Conversation

GeorgeTaveras1231
Copy link

This causes problems because the order of export conditions is critical to how the package will be interpreted.

Example, the following will be improperly sorted

{
  "types": "./f.d.ts",
  "import": "./f.js",
  "default": "./f.cjs"
}

Producing the following invalid config

{
  "default": "./f.cjs"
  "import": "./f.js",
  "types": "./f.d.ts",
}

Issues:

  1. "default" is at the top. "default" should always be last.
  2. "types" is after "import". This is invalid because typescript will use the first matching condition, "import" being a valid condition used by typescript.

PR Checklist

Overview

This causes problems because the order of export conditions is critical to how the package will be interpreted.

Example, the following will be improperly sorted

```json
{
  "types": "./f.d.ts",
  "import": "./f.js",
  "default": "./f.cjs"
}
```

Producing the following invalid config

```json
{
  "default": "./f.cjs"
  "import": "./f.js",
  "types": "./f.d.ts",
}
```

Issues:
1. "default" is at the top. "default" should always be last.
2. "types" is after "import". This is invalid because typescript will use the first matching condition, "import" being a valid condition used by typescript.
@GeorgeTaveras1231
Copy link
Author

GeorgeTaveras1231 commented Feb 27, 2025

The original PR that introduced this assumed a over-simplified scenario. For a more thorough approach for sorting the exports field, see this PR in sort-package-json

@GeorgeTaveras1231 GeorgeTaveras1231 changed the title sort-collections: Remove exports from default fix: sort-collections - Remove exports from default Feb 28, 2025
@GeorgeTaveras1231 GeorgeTaveras1231 changed the title fix: sort-collections - Remove exports from default fix(sort-collections): remove exports from default Feb 28, 2025
@GeorgeTaveras1231 GeorgeTaveras1231 changed the title fix(sort-collections): remove exports from default fix(sort-collections): avoid sorting exports by default Feb 28, 2025
Copy link
Owner

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

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

👍 SGTM. Ideally we like to discuss fixes in issues first, but this one seems straightforward to me (cc @michaelfaith to make sure I haven't missed something obvious).

Just, could you add unit testing please? Since this touches program logic it should also have changes in sort-collections.test.ts. Thanks!

@JoshuaKGoldberg JoshuaKGoldberg added the status: waiting for author Needs an action taken by the original poster label Feb 28, 2025
@michaelfaith
Copy link
Collaborator

👍 SGTM. Ideally we like to discuss fixes in issues first, but this one seems straightforward to me (cc @michaelfaith to make sure I haven't missed something obvious).

Just, could you add unit testing please? Since this touches program logic it should also have changes in sort-collections.test.ts. Thanks!

+1 on the unit tests. @GeorgeTaveras1231 I guess i'd also ask how this relates to the upstream change you have in flight. As in, once that lands and is released, should this be re-enabled?

@GeorgeTaveras1231
Copy link
Author

@JoshuaKGoldberg @michaelfaith thanks for the comment.

I apologize for the carelessly low-touch effort on this PR - I was lazy and had multiple ongoing threads so decided to use the GH code editor and make the change in-line 😅 -- no worries, I will pull down the repo and update the unit tests 👍🏽

@michaelfaith this relates loosely with my other PR because this rule does not use the sort-package-json package.

I think the exports can be re-enabled alongside the imports condition but it would require updating this rule to use sort-package-json or a version of the algorithm implemented there. So the follow-up change won't be as trivial as just re-adding exports to the list of defaults.

@michaelfaith
Copy link
Collaborator

Thanks. And I just noticed the defaults are listed on the doc page for the rule too, so that'll need to be updated as well. 🙏

.tool-versions Outdated
Copy link
Author

Choose a reason for hiding this comment

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

I hope it's not a problem that I committed this. I use asdf for managing tool versions and it's helpful to have these files in the repo. I thought it would help other devs who might use the same tool.

Copy link
Owner

Choose a reason for hiding this comment

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

I like the idea in theory, but in practice:

Could you please split this out of this PR? I'm not opposed to discussing in a separate issue -here or in CTA- but would rather each issue and PR be minimally focused.

@GeorgeTaveras1231
Copy link
Author

@michaelfaith @JoshuaKGoldberg I have a question.

I put a lot of effort into researching and figuring out a robust algorithm for sorting the conditions in exports and imports as well as the paths in those objects. However, in my PR for sort-package-json I'm sensing some resistance to the change.

TBH, I think I'm having some difficulty communicating with the maintainers of that repo; but I get the sense that they don't have a real position on the validity of the algorithm and are just resistant to the change because they don't understand it. (I may be looking to into it).

My question is: Would you be open to me incorporating that algorithm to this ESLint plugin directly? (without using the sort-package-json package).

I work in a large monorepo with hundreds of packages and see a huge benefit to enforcing a predictable order - both in my repo and the open source community -- not only for stylistic reasons, but also to ensure developers avoid unexpected bugs while trying to support multiple runtimes, environments, and syntaxes.

Feel free to look at the other PR if you are curious about the approach - I list a lot of examples showing invalid and valid configurations that the sorter will enforce, as well as links to the resources I used in my research.

Copy link

codecov bot commented Mar 2, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.77%. Comparing base (318b1a8) to head (23e9afe).
Report is 10 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #918      +/-   ##
==========================================
- Coverage   98.77%   98.77%   -0.01%     
==========================================
  Files          21       21              
  Lines        1222     1221       -1     
  Branches      142      142              
==========================================
- Hits         1207     1206       -1     
  Misses         15       15              

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

@JoshuaKGoldberg
Copy link
Owner

having some difficulty communicating

This is a tricky topic to respond to in public 😄. Giving feedback on anything around communication styles, ongoing debates, or other opinion-oriented things can easily look like personal attacks. Please forgive me if anything here looks like that. It's not meant to be criticism, just general advice. (I don't think you'll take anything as pointed, but have in the past seen people misread others' discussions...)

Anyway, this is just my read of this PR and that one:

  • It's only been 2 days 😛. Whatever point creating a fork / new package becomes reasonable is well beyond the scale of days or even weeks.
  • You're asking to significantly increase the scope of that PR. The maintainers there are asking to split up changes to get things in more quickly. Their requests are good and reasonable.
    • Single-purpose PRs allow quick improvements get in sooner without being blocked by resolving bigger discussions. Related: https://www.joshuakgoldberg.com/blog/split-out-unrelated-changes
    • You are posting very long essays. The rest of us are posting short sentences. This is a common symptom of someone trying to use a channel for something it's not meant for.
  • I don't believe "they don't have a real position ... resistant to the change because they don't understand it" is logically supported by the PR discussion.
    • If anything, they've very much understood what you're trying to do, and that's why they're asking to split things up!

Happy to chat more over email on navigating the murky waters of open source politicking. 🙂

Copy link
Owner

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

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

Progress, thanks for sticking with this! 🚀

@@ -132,6 +132,7 @@ ruleTester.run("sort-collections", rule, {
}
}
}`,
options: [["exports"]],
Copy link
Owner

Choose a reason for hiding this comment

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

[Testing] Oh, sorry, I wasn't clear in what I meant to ask for - could you please add a valid test too?

I think there are really two points of logic that are relevant+important to test for this change:

  • By default, the rule does not enforce sorting for "exports"
  • If added to the list in options, "exports" does get sorted

This test checks the latter but not the former.

Copy link
Author

Choose a reason for hiding this comment

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

@JoshuaKGoldberg about this - should we consider warning developers or requiring a separate flag to enable dangerous keys? I think there is an opportunity here to educate people on the dangers of sorting exports and imports alphabetically (while still giving them the choice if this is what they want to do).

Copy link
Owner

Choose a reason for hiding this comment

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

Maybe as a quick mention in the docs file that links to the first-party package.json docs? I don't think a separate flag is justified yet. Someone who reads through the docs to know about the option is probably pretty high intent anyway.

Copy link
Author

Choose a reason for hiding this comment

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

Hahaha that is fair
I'm laughing because I'm realizing I have a cynical tendency to think people will not read the documentation lol

No worries, I will add a note in the docs 👍🏽

Copy link
Author

@GeorgeTaveras1231 GeorgeTaveras1231 Mar 2, 2025

Choose a reason for hiding this comment

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

@JoshuaKGoldberg I think this is my last alignment question.

I was working on the docs and realized that this rule only does a top-level sort (not recursively) so at the moment, it only causes problems if you have a condition object at the top level.

i.e.

This breaks when auto-fixed

{
  "exports": {
    "types": "./f.d.ts",
    "import": "./f.js",
    "default": "./f.cjs"
  }
}

This is ok

{
  "exports": {
    ".": {
      "types": "./f.d.ts",
      "import": "./f.js",
      "default": "./f.cjs"
    }
  }
}

Since the error case is easily distinguishable, it made me think we are putting too much responsibility on the consumer to know wether its safe or not safe to sort.
What do you think about just adding a check to the sorter? - to only sort if its not a condition object (the heuristic per the standards is to check if the keys start with .)

It would be a totally different approach, we may be able to leave exports in the list of defaults but make it safer.

I'm ok with putting this in a separate PR and closing this one, or repurposing this one. What do you think?

@GeorgeTaveras1231
Copy link
Author

@JoshuaKGoldberg, thanks so much for the thoughtful response, constructive feedback, and offer to connect outside of GH. I am grateful that you'd put so much thought into your response when I'm a stranger on the internet lol and in retrospect, I was being a baby about the whole thing 😅

In my defense, I think what I was looking for that I was not getting was validation that this is a real problem and that the approach is sound (hence my comment about them "not understanding it"). I'm totally happy to break up PRs if the scope feels too big - but I don't think that was ever requested in those terms 🤔 I just heard "delete all this unnecessary code" 😅 🤷🏽
I'm on the fence about what to do next - but I may just wait until they give me some form of validation before I break up the PR 🤔

You're still making a lot of good points and giving me great perspective. 🙏🏽 And I'm sorry to make a GH PR thread into a personal therapy session. I think I need an outlet for these long tangential conversations so I may take you up on that offer to connect via email 😌

@michaelfaith
Copy link
Collaborator

If you're thinking of implementing a new sort algorithm rather than removing exports from the default sort, i'd recommend closing this PR out and starting with an issue. We can hash out details about behavior in the issue, and after there's general alignment, then open a PR against the issue. How does that sound?

@GeorgeTaveras1231
Copy link
Author

@michaelfaith That sounds good! I'll go ahead and open an issue proposing the algorithm I worked on - we can use that as a baseline and adjust it after gathering feedback.

@GeorgeTaveras1231
Copy link
Author

@michaelfaith FYI I opened #928 with a proposal. It's a bit lengthy and I apologize for that but take the time to read it if you are interested. This was a good exercise because as I was writing it I discovered issues with my original approach - so I will likely close the PR in sort-package-json. And to be clear, I'm happy to take on the full feature implementation if approved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting for author Needs an action taken by the original poster
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants