Skip to content

feat: updatePackage, sortPackage and normalizePackage utils#240

Merged
pi0 merged 16 commits into
mainfrom
package-utils
Aug 19, 2025
Merged

feat: updatePackage, sortPackage and normalizePackage utils#240
pi0 merged 16 commits into
mainfrom
package-utils

Conversation

@43081j

@43081j 43081j commented Aug 11, 2025

Copy link
Copy Markdown
Member

This is a WIP of the package utils described in #238

Draft until we're happy with the shape, etc.

API design

addPackageJSONDependency(pkg, name, version[, type])

Adds a dependency to the specified dependency list (by the type parameter).

For example:

addPackageJSONDependency(pkg, "picocolors", "^1.0.0", "dev");

// or default prod
addPackageJSONDependency(pkg, "picocolors", "^1.0.0");

Automatically sorts the dependency list you mutated, and handles optional peer dependencies (when type is "optionalPeer").

removePackageJSONDependency(pkg, name[, type])

Removes a dependency from the specified dependency list (by the type parameter`).

For example:

removePackageJSONDependency(pkg, "picocolors");

// or from a specific list
removePackageJSONDependency(pkg, "picocolors", "dev");

Also removes it from optional peer dependencies when type is "optionalPeer".

updatePackageJSON(id, update[, resolveOptions])

Applies a partial update to the package.json found at id (any resolvable string, e.g. a path).

  • All non-dependency list fields are overwritten
  • All dependency list fields are merged

For example:

updatePackageJSON(".", {
  name: "some-package" // will overwrite `name`
});

// Given a `package.json` already containing:
// {
//.  dependencies: {
//.    tinyexec: "^1.0.0"
//   }
// }

updatePackageJSON(".", {
  dependencies: {
    picocolors: "^1.0.0"
  }
});

// Now contains
// {
//.  dependencies: {
//     picocolors: "^1.0.0",
//.    tinyexec: "^1.0.0"
//   }
// }

@43081j 43081j requested a review from pi0 August 11, 2025 08:46
@MichaelDeBoey

Copy link
Copy Markdown

@43081j @pi0 What would you think about convenience methods like removePackageJSONScript btw?
This could replace code like seen in https://github.com/remix-run/grunge-stack/blob/c25307668648b4944e5cd7815c78c098d67ea322/remix.init/index.js#L51-L64

But I would understand if you con't want to add that, as that could lead to a lot of PRs/requests to add others as well

@43081j

43081j commented Aug 11, 2025

Copy link
Copy Markdown
Member Author

we could possibly change the updatePackageJSON method to accept a function like this:

updatePackageJSON('.', (pkg) => ({
  scripts: {
    ...pkg.scripts,
    build: "foo"
  }
}));

@MichaelDeBoey

Copy link
Copy Markdown

@43081j That could definitely be helpful, but in the example given that would still result into

updatePackageJSON('.', ({ scripts: { "": _scriptToRemove, ...scripts } }) => ({
  scripts,
}));

And I actually wanted to avoid doing the destructing myself with a convenience method like removePackageJSONScript 🙈

@43081j

43081j commented Aug 11, 2025

Copy link
Copy Markdown
Member Author

i think in those cases we should just support undefined:

updatePackageJSON('.', {
  scripts: {
    scriptToRemove: undefined
  }
});

this is already supported for top level keys, but not sub keys

@MichaelDeBoey

Copy link
Copy Markdown

@43081j Sounds a good alternative if you ask me!

@pi0

pi0 commented Aug 19, 2025

Copy link
Copy Markdown
Member

Hey thanks for PR! I just had a chance to read through.

updatePackageJSON looks very promising util we can start with.

Supporting the second argument of updatePackageJSON to be a callback originalPkg => newPkg might be useful for writing all transforms based on it (similar to codeup.updateJSON - example usage)

We could have a followup to add some utils like addDependency, etc, but i guess the list might go on for all pkg.json fields. To fix DX issue of assigning default empty fields, maybe we can give a wrapper Proxy(pkgJson) to update callback so if users assign pkg.dependencies.foo and dependencies is undefined, proxy can auto assign a default object.

@pi0

pi0 commented Aug 19, 2025

Copy link
Copy Markdown
Member

Also landed support for package.json5 and package.yaml (#234). Simplified updsatePackage could be replicated if we keep it simply as one updater function.

@MichaelDeBoey

MichaelDeBoey commented Aug 19, 2025

Copy link
Copy Markdown

We could have a followup to add some utils like addDependency, etc, but i guess the list might go on for all pkg.json fields

@pi0 I agree though that we should be careful not to add utilities for all package.json properties.
But having (a couple) convenience method(s) like addDependency would be beneficial imo as that would also sort dependencies list (so not just a basic Object.assign), just like @npmcli/package-json` is doing

@pi0 pi0 changed the title feat: add package utils feat: add updatePackageJSON and normalizePackageJSON utils Aug 19, 2025
@pi0 pi0 changed the title feat: add updatePackageJSON and normalizePackageJSON utils feat: updatePackageJSON, sortPackageJSON and normalizePackageJSON Aug 19, 2025
Comment thread src/packagejson/utils.ts
@pi0

pi0 commented Aug 19, 2025

Copy link
Copy Markdown
Member

Updated utils to match #234 functionality we also talked with @43081j to only land updatePackage with a callback to keep it most flexible. add/remove utils might be added in the future.

@pi0 pi0 changed the title feat: updatePackageJSON, sortPackageJSON and normalizePackageJSON feat: updatePackage, sortPackage and normalizePackage utils Aug 19, 2025
@pi0 pi0 changed the title feat: updatePackage, sortPackage and normalizePackage utils feat: updatePackage, sortPackage and normalizePackage utils Aug 19, 2025
@pi0 pi0 marked this pull request as ready for review August 19, 2025 16:59
Comment thread src/packagejson/utils.ts
@pi0 pi0 merged commit 3363806 into main Aug 19, 2025
3 checks passed
@pi0 pi0 deleted the package-utils branch August 19, 2025 22:51
@MichaelDeBoey MichaelDeBoey mentioned this pull request Aug 19, 2025
1 task
@outslept outslept mentioned this pull request Aug 20, 2025
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants