Skip to content

feat: sort dependencies according to detected package manager, support devEngines field - #382

Merged
keithamus merged 23 commits into
keithamus:mainfrom
Tobbe:tobbe-feat-package-manager-specific-sort
Dec 14, 2025
Merged

feat: sort dependencies according to detected package manager, support devEngines field#382
keithamus merged 23 commits into
keithamus:mainfrom
Tobbe:tobbe-feat-package-manager-specific-sort

Conversation

@Tobbe

@Tobbe Tobbe commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

Different package managers sort dependencies using different sorting orders. This PR tries to detect the package manager that's used by the project, and chooses the sorting order based on the detected package manager

Fixes #363

keithamus
keithamus previously approved these changes Dec 5, 2025

@keithamus keithamus left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I'd like @fisker to review this though, and perhaps @pfe-nazaries who also commented in #363

Comment thread index.js Outdated
Comment thread index.js Outdated
Comment thread index.js Outdated
@fisker

fisker commented Dec 7, 2025

Copy link
Copy Markdown
Collaborator

@Tobbe I pushed a refactor to simplify logic and reduce diff, can you check if there are adjustments (I didn't check comments) needed?

Comment thread index.js Outdated
Comment thread index.js Outdated
Comment thread index.js Outdated
Comment thread index.js Outdated
const hasYarnOrPnpmLock = (packageJson) => {
if (!cache.has(packageJson)) {
cache.set(
packageJson,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@keithamus Do you think we should cache this based on process.cwd()?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe also detect .yarn dir, .yarnrc.yml, pnpm-workspace.yaml

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Sounds reasonable yes.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

@Tobbe

The one thing that's left to resolve is the caching. There's a comment regarding using cwd that I don't fully understand. Was the idea to use only process.cwd(), or both process.cwd() and packageJson together?

You can memoize this function by the process.cwd(), as it should invariably return the same answer for a single execution. The packageJson is irrelevant as it's not an input to the question this function answers, only the directory is. So I would remove the packageJson arg and use a dir arg (and change the calls to check the dir + filename).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I had to add cache.clear() to the start of sortPackageJson() for tests to pass. Since they're all using the same dir they'll reuse the same cache entry

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I could mock process.cwd() in the tests instead if you prefer

@Tobbe

Tobbe commented Dec 13, 2025

Copy link
Copy Markdown
Contributor Author

I've merged in the latest code from main and fixed merge conflicts.
I've also addressed the remaining review comments, except one.

The one thing that's left to resolve is the caching. There's a comment regarding using cwd that I don't fully understand. Was the idea to use only process.cwd(), or both process.cwd() and packageJson together?

@fisker

fisker commented Dec 13, 2025

Copy link
Copy Markdown
Collaborator

I made a minor refactor 854af79 (#382)

fisker
fisker previously approved these changes Dec 13, 2025
Comment thread index.js Outdated
}

function sortPackageJson(jsonIsh, options = {}) {
cache.clear()

@fisker fisker Dec 13, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we are doing this, maybe just use a variable instead? (sorry, didn't notice this change)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

But this makes the cache meaningless. Let's remove it, mock process.cwd() instead in test.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'll fix.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think clearing the cache once at the start makes the cache meaningless. sortDependencies is called multiple times during one execution of sortPackageJson(), each of those sortDependencies invocations could potentially try to read the filesystem, which the cache still prevents even when clearing it once at the start

@Tobbe

Tobbe commented Dec 13, 2025

Copy link
Copy Markdown
Contributor Author

I made a minor refactor 854af79 (#382)

I did fs.existsSync(path.join(dir, 'yarn.lock')) etc because @keithamus wanted me to include both the dir and the filename, as you can see in his comment here: #382 (comment)

He also wanted me to pass the dir to the function (same comment, #382 (comment))

@fisker you have now removed both those changes. So I'll let you two decide what solution you want here 🙂

@fisker

fisker commented Dec 13, 2025

Copy link
Copy Markdown
Collaborator

He also wanted me to pass the dir to the function

There is no difference between pass or call it in hasYarnOrPnpmFiles, but move it to hasYarnOrPnpmFiles we can omit path.join call.

fisker
fisker previously approved these changes Dec 13, 2025
Comment thread index.js Outdated
packageJson.pnpm ||
(typeof packageManager === 'string' &&
(packageManager.startsWith('yarn@') ||
packageManager.startsWith('pnpm@')))

@fisker fisker Dec 13, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe corepack also support {packageManager: 'npm@1.0.0'}?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah, turns out packageManager can also be an object. bb0c487 (#382)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

And there are devEngines.packageManager ...

9fab533 (#382)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Maybe corepack also support {packageManager: 'npm@1.0.0'}?

No, npm is not supported as a value for packageManager: nodejs/node#51888

fisker
fisker previously approved these changes Dec 13, 2025
Comment thread index.js Outdated
Comment thread tests/dependency-sorting.js Outdated
Comment thread tests/dependency-sorting.js Outdated
@fisker fisker changed the title feat: sort dependencies according to detected package manager feat: sort dependencies according to detected package manager, support devEngines field Dec 13, 2025
fisker
fisker previously approved these changes Dec 13, 2025
Comment thread index.js
? { ...object, [property]: over(object[property], ...args) }
: object
: object,
)

@fisker fisker Dec 13, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@keithamus This should be a bug, we didn't check the object is not null or undefined before, so it can crash. Some other changes removing onObject in this PR also related to this. Found this adding support for devEngines, do you want me to extract this part to separated PRs?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Nice find! We can keep it here.


// packageManager
t.deepEqual(
getDependencyOrders({ packageManager: 'npm@1.0.0' }, () => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

npm is not supported as a value for packageManager nodejs/node#51888

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Should we block on this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Block this PR you mean? No, I'd rather get it merged

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Great! Merged then 😉

Comment thread index.js
? { ...object, [property]: over(object[property], ...args) }
: object
: object,
)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Nice find! We can keep it here.

@keithamus
keithamus merged commit e3f2370 into keithamus:main Dec 14, 2025
3 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 3.6.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@keithamus

Copy link
Copy Markdown
Owner

Thanks for your work on this @Tobbe!

@Tobbe

Tobbe commented Dec 14, 2025

Copy link
Copy Markdown
Contributor Author

@keithamus and @fisker Thanks for guiding me through this 🙏

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sorting algorithm fights yarn

3 participants