-
Notifications
You must be signed in to change notification settings - Fork 55
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
Prioritize direct dependency if available #192
base: master
Are you sure you want to change the base?
Prioritize direct dependency if available #192
Conversation
src/cli.ts
Outdated
@@ -63,10 +65,12 @@ if (strategy !== 'highest' && strategy !== 'fewer') { | |||
|
|||
try { | |||
const yarnLock = fs.readFileSync(file, 'utf8'); | |||
const packageJson = packageJsonPath ? fs.readFileSync(packageJsonPath, 'utf8') : undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I rather use null
instead of undefined
in this case. It feels more explicit to me.
version "0.1.0" | ||
resolved "http://example.com/a-package/0.1.0" | ||
|
||
other-package@>=1.0.0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should remove any mention to other-package
in this test, as it is not related to the test intention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually important as it verifies that packages that are not in package.json fall back to the highest
strategy.
|
||
test('prioritizes direct requirements if present', () => { | ||
const yarn_lock = outdent` | ||
a-package@*: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally (and I acknowledge this is slightly out of the scope of the PR), we should use a similar yarn.lock
to test all strategies (i.e. the first two tests in this file). That way it's more clear what's the different behaviour of each strategy.
Interesting idea. I do see the problem you are trying to solve, and this seems like a neat solution. You mentioned I think this should be its own strategy, let's call it On a higher level, this PR highlight the deeper problem of not having control of which version is used to deduplicate. Using strategies is just a proxy to automatically select the versions. Using Before merging this PR I'd like to see:
I may help with those if you want, but I can't commit to a timeline right now. |
@@ -107,9 +137,15 @@ const computePackageInstances = (packages: Packages, name: string, useMostCommon | |||
// Extract the list of unique versions for this package | |||
const versions:Versions = new Map(); | |||
for (const packageInstance of packageInstances) { | |||
if (versions.has(packageInstance.installedVersion)) continue; | |||
if (versions.has(packageInstance.installedVersion)) { | |||
const existingPackage = versions.get(packageInstance.installedVersion)!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get why we need to add isDirectDependency
to every dep in the tree.
Wouldn't checking directDependencies.has(entryName)
when sorting the versions (line 177) suffice? Especially when we encapsulate this logic into its own strategy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've moved this down here so only Version
needs the isDirectDependency
flag. There's no entryName
to check in the version sorting step so it's not that easy to do it there. If we absolutely want to avoid having this, I suppose it's possible to loop over satisfies
in the sorting function and check if any requested version is a direct dependency but that'd just be worse for performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback, I'll rework it into a strategy instead.
version "0.1.0" | ||
resolved "http://example.com/a-package/0.1.0" | ||
|
||
other-package@>=1.0.0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually important as it verifies that packages that are not in package.json fall back to the highest
strategy.
0412618
to
489381a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this?
@@ -13,7 +13,7 @@ program | |||
.usage('[options] [yarn.lock path (default: yarn.lock)]') | |||
.option( | |||
'-s, --strategy <strategy>', | |||
'deduplication strategy. Valid values: fewer, highest. Default is "highest"', | |||
'deduplication strategy. Valid values: fewer, highest, direct.', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commander already shows the default value so I removed Default is "highest"
as it was redundant.
@@ -107,9 +137,15 @@ const computePackageInstances = (packages: Packages, name: string, useMostCommon | |||
// Extract the list of unique versions for this package | |||
const versions:Versions = new Map(); | |||
for (const packageInstance of packageInstances) { | |||
if (versions.has(packageInstance.installedVersion)) continue; | |||
if (versions.has(packageInstance.installedVersion)) { | |||
const existingPackage = versions.get(packageInstance.installedVersion)!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've moved this down here so only Version
needs the isDirectDependency
flag. There's no entryName
to check in the version sorting step so it's not that easy to do it there. If we absolutely want to avoid having this, I suppose it's possible to loop over satisfies
in the sorting function and check if any requested version is a direct dependency but that'd just be worse for performance.
Sorry, I haven't been available to review this change. I'll have a look as soon as possible. |
This would actually be nice to have :) |
This is more of a proof of concept and request for comments. This PR adds support for prioritizing direct dependencies (ones listed in
package.json
).For example, if our
package.json
has the followingat the time of writing, this will result in these yarn.lock entries
@types/react-redux
pulls in@types/react@*
which is correct since it does work with any react version. However, this is problematic for us since when we use the react-redux types, it leaks in the newer react 18 types which are not compatible with the react 17 types. So we absolutely want both to resolve to17.0.49
.This can be worked around using yarn resolutions which is what we're doing now but it would be nice if yarn-deduplicate could do this for us.
With the default
highest
strategy, these won't be deduplicated. We could usefewer
to deduplicate here but that affects everything else but we'd rather it apply only to direct dependencies like@types/react
here.This PR adds a
--package-json
flag which you can point to an existingpackage.json
where it can get information on which versions are direct dependencies and then prioritizes those on top of whatever strategy is picked.Is this sound? I'm not too confident with how this interacts with strategies (and should this be a strategy in itself?)