The problem
A package.json dependency gets neither the yank check nor the vulnerability check. The README gives one reason for both: a dependency there "declares a range rather than a version, and the version that range resolves to is recorded in the lock file, which Update-time does not read; auditing that lock file is what npm audit is for."
That holds for a range, and not for "react": "17.0.2". npm reads a bare version as an exact version, and the README itself points at that spelling as the way to opt a dependency out: "pin an exact version to opt it out of automatic updates entirely, just like with Python dependencies." Such a dependency names the version the run leaves it on, which is the one thing both checks need — the same reasoning that makes a == pin in a requirements.txt checkable.
Both sources are already reachable. npmjs.deprecation() reads a version's deprecation from the registry and is what reports a deprecated jsDelivr URL in the yank's wording. OSV's npm ecosystem is already queried, for those same jsDelivr URLs. And package_json.dependency_locations() already locates each declaration at the line declaring it.
How often this happens
Checked before writing this issue rather than assumed: of the three package.json files in a real project (quality-time's docs, renderer, and frontend), none of the 50 dependencies declares a bare version — every one uses a range. npm's convention is ^, so this gap may be rare in practice, which is worth weighing against the two above before scheduling it.
Scope
- Recognise a dependency whose spec is a bare version, in the sections
dependency_locations already reads (dependencies, devDependencies, optionalDependencies).
- Check that version for a deprecation on the npm registry, and report it in the wording a yanked dependency gets, as a deprecated jsDelivr version already is.
- Check that version against OSV's npm advisories, and report it as any other vulnerable reference, at the line declaring it.
- Leave every range-declared dependency exactly as it is.
Out of scope
- Reading
package-lock.json or pnpm-lock.yaml to resolve a range to a version. That is what npm audit and pnpm audit do properly, and it is the scope line the README already draws.
- Updating. An exact pin is how a dependency is opted out of updates, npm and pnpm leave it where it is, and this issue adds warnings only.
- Markers.
package.json is strict JSON with nowhere to put a comment, so neither warning can be silenced per dependency, which is already true of everything else in that file.
Documentation
- The per-type "Yanked dependencies" and "Vulnerable dependencies" answers for npm and pnpm dependencies, which currently say neither check applies and why.
- The npm rows in the dependency-type tables under "Yanked dependencies" and "Vulnerable dependencies".
- A changelog entry under
[Unreleased].
Open questions
- Does a range that admits exactly one version count as exact —
=1.2.3, or 1.2.3 - 1.2.3 — or only a bare version, which is the spelling the README already tells people to use?
- Do both checks apply to
optionalDependencies as well as dependencies and devDependencies, given that an optional dependency may not be installed at all?
- Is a deprecation worth reporting for a version the run deliberately leaves alone, or does it only add noise to a pin the project has already decided to keep?
The problem
A
package.jsondependency gets neither the yank check nor the vulnerability check. The README gives one reason for both: a dependency there "declares a range rather than a version, and the version that range resolves to is recorded in the lock file, which Update-time does not read; auditing that lock file is whatnpm auditis for."That holds for a range, and not for
"react": "17.0.2". npm reads a bare version as an exact version, and the README itself points at that spelling as the way to opt a dependency out: "pin an exact version to opt it out of automatic updates entirely, just like with Python dependencies." Such a dependency names the version the run leaves it on, which is the one thing both checks need — the same reasoning that makes a==pin in arequirements.txtcheckable.Both sources are already reachable.
npmjs.deprecation()reads a version's deprecation from the registry and is what reports a deprecated jsDelivr URL in the yank's wording. OSV's npm ecosystem is already queried, for those same jsDelivr URLs. Andpackage_json.dependency_locations()already locates each declaration at the line declaring it.How often this happens
Checked before writing this issue rather than assumed: of the three
package.jsonfiles in a real project (quality-time'sdocs,renderer, andfrontend), none of the 50 dependencies declares a bare version — every one uses a range. npm's convention is^, so this gap may be rare in practice, which is worth weighing against the two above before scheduling it.Scope
dependency_locationsalready reads (dependencies,devDependencies,optionalDependencies).Out of scope
package-lock.jsonorpnpm-lock.yamlto resolve a range to a version. That is whatnpm auditandpnpm auditdo properly, and it is the scope line the README already draws.package.jsonis strict JSON with nowhere to put a comment, so neither warning can be silenced per dependency, which is already true of everything else in that file.Documentation
[Unreleased].Open questions
=1.2.3, or1.2.3 - 1.2.3— or only a bare version, which is the spelling the README already tells people to use?optionalDependenciesas well asdependenciesanddevDependencies, given that an optional dependency may not be installed at all?