chore: update eslint unicorn plugin to v65 - #8838
Conversation
Overall package sizeSelf size: 7.49 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.3.2 | 124.41 kB | 440.65 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #8838 +/- ##
========================================
Coverage 98.44% 98.45%
========================================
Files 943 943
Lines 127310 127336 +26
Branches 10824 11150 +326
========================================
+ Hits 125335 125365 +30
+ Misses 1975 1971 -4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 68a36e8 | Docs | Datadog PR Page | Give us feedback! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8343534888
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
BenchmarksBenchmark execution time: 2026-07-22 19:39:16 Comparing candidate commit 68a36e8 in PR branch Found 7 performance improvements and 0 performance regressions! Performance is the same for 2311 metrics, 40 unstable metrics.
|
48e9f2d to
0c84e24
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c3c3c5153f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
0ec88ef to
c20c8ce
Compare
ac8e681 to
3aaac6e
Compare
| * @returns {string | undefined} | ||
| */ | ||
| function getSegment (string, separator, index, fallback) { | ||
| let start = 0 |
There was a problem hiding this comment.
Nit: Since the indexes are only ever 0 or 1 for now, can we add a fast path to this function?
There was a problem hiding this comment.
I can not imagine faster code for that.
Do you have a suggestion?
IlyasShabi
left a comment
There was a problem hiding this comment.
LGTM specially on at() split getSegment and jsdoc
3aaac6e to
edfcbae
Compare
Reading `str.split(sep)[i]` allocates the full segment array, and the unicorn rule's `split(sep, i + 1)[i]` rewrite is worse for a string separator: passing a limit drops V8 off its constant-limit fast path, paying a per-call ToUint32 plus the array allocation. `getSegment` scans with `indexOf` and slices out the one segment the caller wants. Node 24.15 / V8 13.6, 5M ops x 7 trials, drop best+worst: " " [1] helper 24.6ns split 30.6ns (-20%) split+limit 86.6ns "-" [0] helper 25.4ns split 35.9ns (-29%) split+limit 74.3ns "." [0] helper 16.0ns split 36.4ns (-56%) split+limit 67.2ns
The unicorn autofix touched branches no existing spec exercised: 1. ws: a connection carrying x-forwarded-proto now asserts the server span's http.url resolves to wss, reaching getRequestProtocol's proxy arm (and the getSegment call inside it). 2. oracledb: a callback-form pool.getConnection pins the callback path, which only the promise form covered before. The ai-sdk `messages.findLast(...)` arm is left for the PR author: covering it needs a VCR cassette recorded against a real OPENAI_API_KEY, since the test agent matches cassettes by request body and runs CI in 404-on-miss mode. Test-only, no production code changes.
…and setObjectGenerationTags The two methods use promptInfo.messages.findLast() when the caller passes a messages array without a top-level prompt string. Existing tests all use the prompt: '' form, which short-circuits to promptInfo.prompt and leaves lines 234 and 250 uncovered. Both new tests use an inline mock fetch (same pattern as the prompt-cache capture tests), bypassing the VCR proxy so no cassette recording is needed: - generateText with messages: array and three turns verifies that the last user message is extracted as inputValue. - generateObject with output: 'no-schema' and the same messages array verifies the same path in setObjectGenerationTags. Both tests skip ai < 5.0.0 where the mock-fetch provider wiring differs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The wrapper declared `wrappedHook (...args)`, which materialises a fresh args array on every fastify hook invocation, including the common case where none of the wrap-fed channels has a subscriber. Forward the `arguments` object untouched on the fast path and copy or index it only in the slow path, so the default request path allocates nothing.
…lugin-import-x The eslint 9->10 and unicorn 65->68 bumps turn on a large set of new recommended rules. The newly-firing ones are deactivated in the config with per-rule counts, grouped by intent (autofixable follow-up, needs-audit, never-activate), so this bump stays free of production source churn; enabling them is left to follow-ups. Some deactivated rules may surface real bugs (unicorn/no-duplicate-logical-operands, no-duplicate-if-branches, no-loop-iterable-mutation, and the core no-unassigned-vars); their config comments flag them for a focused audit. Changes the bump requires directly: 1. Port the repo's custom eslint rules to the v10 context API; context.getSourceCode() was removed in favour of context.sourceCode. 2. eslint 10 drops Node.js 18, so .nvmrc moves to 22. 3. Rename getRunInChildContextSubtype and drop an unnecessary String.raw to satisfy the two rules kept on (consistent-compound-words, prefer-string-raw). 4. Remove stale unicorn/no-array-for-each disable directives; the rule was renamed to no-for-each, which is deactivated here.
The message extraction tests referenced a helper that does not exist, so lint failed before the versioned provider fixture could load.
The validation code landed after the branch's previous base, so Unicorn 68's new checks only surfaced once the branch was rebased.
npm list represents hoisted transitive packages without a resolved URL. Skipping those entries makes the local license gate report valid attributions as extraneous when the root dependency graph no longer supplies the same package.
edfcbae to
68a36e8
Compare
* chore: update eslint unicorn plugin to v65 * fixup! * perf(core): replace split-then-index with an allocation-free getSegment Reading `str.split(sep)[i]` allocates the full segment array, and the unicorn rule's `split(sep, i + 1)[i]` rewrite is worse for a string separator: passing a limit drops V8 off its constant-limit fast path, paying a per-call ToUint32 plus the array allocation. `getSegment` scans with `indexOf` and slices out the one segment the caller wants. Node 24.15 / V8 13.6, 5M ops x 7 trials, drop best+worst: " " [1] helper 24.6ns split 30.6ns (-20%) split+limit 86.6ns "-" [0] helper 25.4ns split 35.9ns (-29%) split+limit 74.3ns "." [0] helper 16.0ns split 36.4ns (-56%) split+limit 67.2ns * test: cover uncovered diff lines from the unicorn v65 rewrite The unicorn autofix touched branches no existing spec exercised: 1. ws: a connection carrying x-forwarded-proto now asserts the server span's http.url resolves to wss, reaching getRequestProtocol's proxy arm (and the getSegment call inside it). 2. oracledb: a callback-form pool.getConnection pins the callback path, which only the promise form covered before. The ai-sdk `messages.findLast(...)` arm is left for the PR author: covering it needs a VCR cassette recorded against a real OPENAI_API_KEY, since the test agent matches cassettes by request body and runs CI in 404-on-miss mode. Test-only, no production code changes. * test(ai): cover the messages.findLast() arm in setTextGenerationTags and setObjectGenerationTags The two methods use promptInfo.messages.findLast() when the caller passes a messages array without a top-level prompt string. Existing tests all use the prompt: '' form, which short-circuits to promptInfo.prompt and leaves lines 234 and 250 uncovered. Both new tests use an inline mock fetch (same pattern as the prompt-cache capture tests), bypassing the VCR proxy so no cassette recording is needed: - generateText with messages: array and three turns verifies that the last user message is extracted as inputValue. - generateObject with output: 'no-schema' and the same messages array verifies the same path in setObjectGenerationTags. Both tests skip ai < 5.0.0 where the mock-fetch provider wiring differs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * perf(fastify): keep the addHook wrapper allocation-free on the fast path The wrapper declared `wrappedHook (...args)`, which materialises a fresh args array on every fastify hook invocation, including the common case where none of the wrap-fed channels has a subscriber. Forward the `arguments` object untouched on the fast path and copy or index it only in the slow path, so the default request path allocates nothing. * chore(deps): update eslint to v10, unicorn to v68, switch to eslint-plugin-import-x The eslint 9->10 and unicorn 65->68 bumps turn on a large set of new recommended rules. The newly-firing ones are deactivated in the config with per-rule counts, grouped by intent (autofixable follow-up, needs-audit, never-activate), so this bump stays free of production source churn; enabling them is left to follow-ups. Some deactivated rules may surface real bugs (unicorn/no-duplicate-logical-operands, no-duplicate-if-branches, no-loop-iterable-mutation, and the core no-unassigned-vars); their config comments flag them for a focused audit. Changes the bump requires directly: 1. Port the repo's custom eslint rules to the v10 context API; context.getSourceCode() was removed in favour of context.sourceCode. 2. eslint 10 drops Node.js 18, so .nvmrc moves to 22. 3. Rename getRunInChildContextSubtype and drop an unnecessary String.raw to satisfy the two rules kept on (consistent-compound-words, prefer-string-raw). 4. Remove stale unicorn/no-array-for-each disable directives; the rule was renamed to no-for-each, which is deactivated here. * chore: deduplicate yarn.lock * Apply suggestion from @BridgeAR * test(llmobs): use installed OpenAI fixture version The message extraction tests referenced a helper that does not exist, so lint failed before the versioned provider fixture could load. * ci(lint): update validation code for unicorn v68 The validation code landed after the branch's previous base, so Unicorn 68's new checks only surfaced once the branch was rebased. * chore(lint): use Array.at for latest Cypress screenshot handler * test(cypress): cover latest manual screenshot handler * ci(licenses): include deduplicated vendor dependencies npm list represents hoisted transitive packages without a resolved URL. Skipping those entries makes the local license gate report valid attributions as extraneous when the root dependency graph no longer supplies the same package. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: dd-octo-sts[bot] <200755185+dd-octo-sts[bot]@users.noreply.github.com>
* chore: update eslint unicorn plugin to v65 * fixup! * perf(core): replace split-then-index with an allocation-free getSegment Reading `str.split(sep)[i]` allocates the full segment array, and the unicorn rule's `split(sep, i + 1)[i]` rewrite is worse for a string separator: passing a limit drops V8 off its constant-limit fast path, paying a per-call ToUint32 plus the array allocation. `getSegment` scans with `indexOf` and slices out the one segment the caller wants. Node 24.15 / V8 13.6, 5M ops x 7 trials, drop best+worst: " " [1] helper 24.6ns split 30.6ns (-20%) split+limit 86.6ns "-" [0] helper 25.4ns split 35.9ns (-29%) split+limit 74.3ns "." [0] helper 16.0ns split 36.4ns (-56%) split+limit 67.2ns * test: cover uncovered diff lines from the unicorn v65 rewrite The unicorn autofix touched branches no existing spec exercised: 1. ws: a connection carrying x-forwarded-proto now asserts the server span's http.url resolves to wss, reaching getRequestProtocol's proxy arm (and the getSegment call inside it). 2. oracledb: a callback-form pool.getConnection pins the callback path, which only the promise form covered before. The ai-sdk `messages.findLast(...)` arm is left for the PR author: covering it needs a VCR cassette recorded against a real OPENAI_API_KEY, since the test agent matches cassettes by request body and runs CI in 404-on-miss mode. Test-only, no production code changes. * test(ai): cover the messages.findLast() arm in setTextGenerationTags and setObjectGenerationTags The two methods use promptInfo.messages.findLast() when the caller passes a messages array without a top-level prompt string. Existing tests all use the prompt: '' form, which short-circuits to promptInfo.prompt and leaves lines 234 and 250 uncovered. Both new tests use an inline mock fetch (same pattern as the prompt-cache capture tests), bypassing the VCR proxy so no cassette recording is needed: - generateText with messages: array and three turns verifies that the last user message is extracted as inputValue. - generateObject with output: 'no-schema' and the same messages array verifies the same path in setObjectGenerationTags. Both tests skip ai < 5.0.0 where the mock-fetch provider wiring differs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * perf(fastify): keep the addHook wrapper allocation-free on the fast path The wrapper declared `wrappedHook (...args)`, which materialises a fresh args array on every fastify hook invocation, including the common case where none of the wrap-fed channels has a subscriber. Forward the `arguments` object untouched on the fast path and copy or index it only in the slow path, so the default request path allocates nothing. * chore(deps): update eslint to v10, unicorn to v68, switch to eslint-plugin-import-x The eslint 9->10 and unicorn 65->68 bumps turn on a large set of new recommended rules. The newly-firing ones are deactivated in the config with per-rule counts, grouped by intent (autofixable follow-up, needs-audit, never-activate), so this bump stays free of production source churn; enabling them is left to follow-ups. Some deactivated rules may surface real bugs (unicorn/no-duplicate-logical-operands, no-duplicate-if-branches, no-loop-iterable-mutation, and the core no-unassigned-vars); their config comments flag them for a focused audit. Changes the bump requires directly: 1. Port the repo's custom eslint rules to the v10 context API; context.getSourceCode() was removed in favour of context.sourceCode. 2. eslint 10 drops Node.js 18, so .nvmrc moves to 22. 3. Rename getRunInChildContextSubtype and drop an unnecessary String.raw to satisfy the two rules kept on (consistent-compound-words, prefer-string-raw). 4. Remove stale unicorn/no-array-for-each disable directives; the rule was renamed to no-for-each, which is deactivated here. * chore: deduplicate yarn.lock * Apply suggestion from @BridgeAR * test(llmobs): use installed OpenAI fixture version The message extraction tests referenced a helper that does not exist, so lint failed before the versioned provider fixture could load. * ci(lint): update validation code for unicorn v68 The validation code landed after the branch's previous base, so Unicorn 68's new checks only surfaced once the branch was rebased. * chore(lint): use Array.at for latest Cypress screenshot handler * test(cypress): cover latest manual screenshot handler * ci(licenses): include deduplicated vendor dependencies npm list represents hoisted transitive packages without a resolved URL. Skipping those entries makes the local license gate report valid attributions as extraneous when the root dependency graph no longer supplies the same package. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: dd-octo-sts[bot] <200755185+dd-octo-sts[bot]@users.noreply.github.com>
* chore: update eslint unicorn plugin to v65 * fixup! * perf(core): replace split-then-index with an allocation-free getSegment Reading `str.split(sep)[i]` allocates the full segment array, and the unicorn rule's `split(sep, i + 1)[i]` rewrite is worse for a string separator: passing a limit drops V8 off its constant-limit fast path, paying a per-call ToUint32 plus the array allocation. `getSegment` scans with `indexOf` and slices out the one segment the caller wants. Node 24.15 / V8 13.6, 5M ops x 7 trials, drop best+worst: " " [1] helper 24.6ns split 30.6ns (-20%) split+limit 86.6ns "-" [0] helper 25.4ns split 35.9ns (-29%) split+limit 74.3ns "." [0] helper 16.0ns split 36.4ns (-56%) split+limit 67.2ns * test: cover uncovered diff lines from the unicorn v65 rewrite The unicorn autofix touched branches no existing spec exercised: 1. ws: a connection carrying x-forwarded-proto now asserts the server span's http.url resolves to wss, reaching getRequestProtocol's proxy arm (and the getSegment call inside it). 2. oracledb: a callback-form pool.getConnection pins the callback path, which only the promise form covered before. The ai-sdk `messages.findLast(...)` arm is left for the PR author: covering it needs a VCR cassette recorded against a real OPENAI_API_KEY, since the test agent matches cassettes by request body and runs CI in 404-on-miss mode. Test-only, no production code changes. * test(ai): cover the messages.findLast() arm in setTextGenerationTags and setObjectGenerationTags The two methods use promptInfo.messages.findLast() when the caller passes a messages array without a top-level prompt string. Existing tests all use the prompt: '' form, which short-circuits to promptInfo.prompt and leaves lines 234 and 250 uncovered. Both new tests use an inline mock fetch (same pattern as the prompt-cache capture tests), bypassing the VCR proxy so no cassette recording is needed: - generateText with messages: array and three turns verifies that the last user message is extracted as inputValue. - generateObject with output: 'no-schema' and the same messages array verifies the same path in setObjectGenerationTags. Both tests skip ai < 5.0.0 where the mock-fetch provider wiring differs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * perf(fastify): keep the addHook wrapper allocation-free on the fast path The wrapper declared `wrappedHook (...args)`, which materialises a fresh args array on every fastify hook invocation, including the common case where none of the wrap-fed channels has a subscriber. Forward the `arguments` object untouched on the fast path and copy or index it only in the slow path, so the default request path allocates nothing. * chore(deps): update eslint to v10, unicorn to v68, switch to eslint-plugin-import-x The eslint 9->10 and unicorn 65->68 bumps turn on a large set of new recommended rules. The newly-firing ones are deactivated in the config with per-rule counts, grouped by intent (autofixable follow-up, needs-audit, never-activate), so this bump stays free of production source churn; enabling them is left to follow-ups. Some deactivated rules may surface real bugs (unicorn/no-duplicate-logical-operands, no-duplicate-if-branches, no-loop-iterable-mutation, and the core no-unassigned-vars); their config comments flag them for a focused audit. Changes the bump requires directly: 1. Port the repo's custom eslint rules to the v10 context API; context.getSourceCode() was removed in favour of context.sourceCode. 2. eslint 10 drops Node.js 18, so .nvmrc moves to 22. 3. Rename getRunInChildContextSubtype and drop an unnecessary String.raw to satisfy the two rules kept on (consistent-compound-words, prefer-string-raw). 4. Remove stale unicorn/no-array-for-each disable directives; the rule was renamed to no-for-each, which is deactivated here. * chore: deduplicate yarn.lock * Apply suggestion from @BridgeAR * test(llmobs): use installed OpenAI fixture version The message extraction tests referenced a helper that does not exist, so lint failed before the versioned provider fixture could load. * ci(lint): update validation code for unicorn v68 The validation code landed after the branch's previous base, so Unicorn 68's new checks only surfaced once the branch was rebased. * chore(lint): use Array.at for latest Cypress screenshot handler * test(cypress): cover latest manual screenshot handler * ci(licenses): include deduplicated vendor dependencies npm list represents hoisted transitive packages without a resolved URL. Skipping those entries makes the local license gate report valid attributions as extraneous when the root dependency graph no longer supplies the same package. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: dd-octo-sts[bot] <200755185+dd-octo-sts[bot]@users.noreply.github.com>
* chore: update eslint unicorn plugin to v65 * fixup! * perf(core): replace split-then-index with an allocation-free getSegment Reading `str.split(sep)[i]` allocates the full segment array, and the unicorn rule's `split(sep, i + 1)[i]` rewrite is worse for a string separator: passing a limit drops V8 off its constant-limit fast path, paying a per-call ToUint32 plus the array allocation. `getSegment` scans with `indexOf` and slices out the one segment the caller wants. Node 24.15 / V8 13.6, 5M ops x 7 trials, drop best+worst: " " [1] helper 24.6ns split 30.6ns (-20%) split+limit 86.6ns "-" [0] helper 25.4ns split 35.9ns (-29%) split+limit 74.3ns "." [0] helper 16.0ns split 36.4ns (-56%) split+limit 67.2ns * test: cover uncovered diff lines from the unicorn v65 rewrite The unicorn autofix touched branches no existing spec exercised: 1. ws: a connection carrying x-forwarded-proto now asserts the server span's http.url resolves to wss, reaching getRequestProtocol's proxy arm (and the getSegment call inside it). 2. oracledb: a callback-form pool.getConnection pins the callback path, which only the promise form covered before. The ai-sdk `messages.findLast(...)` arm is left for the PR author: covering it needs a VCR cassette recorded against a real OPENAI_API_KEY, since the test agent matches cassettes by request body and runs CI in 404-on-miss mode. Test-only, no production code changes. * test(ai): cover the messages.findLast() arm in setTextGenerationTags and setObjectGenerationTags The two methods use promptInfo.messages.findLast() when the caller passes a messages array without a top-level prompt string. Existing tests all use the prompt: '' form, which short-circuits to promptInfo.prompt and leaves lines 234 and 250 uncovered. Both new tests use an inline mock fetch (same pattern as the prompt-cache capture tests), bypassing the VCR proxy so no cassette recording is needed: - generateText with messages: array and three turns verifies that the last user message is extracted as inputValue. - generateObject with output: 'no-schema' and the same messages array verifies the same path in setObjectGenerationTags. Both tests skip ai < 5.0.0 where the mock-fetch provider wiring differs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * perf(fastify): keep the addHook wrapper allocation-free on the fast path The wrapper declared `wrappedHook (...args)`, which materialises a fresh args array on every fastify hook invocation, including the common case where none of the wrap-fed channels has a subscriber. Forward the `arguments` object untouched on the fast path and copy or index it only in the slow path, so the default request path allocates nothing. * chore(deps): update eslint to v10, unicorn to v68, switch to eslint-plugin-import-x The eslint 9->10 and unicorn 65->68 bumps turn on a large set of new recommended rules. The newly-firing ones are deactivated in the config with per-rule counts, grouped by intent (autofixable follow-up, needs-audit, never-activate), so this bump stays free of production source churn; enabling them is left to follow-ups. Some deactivated rules may surface real bugs (unicorn/no-duplicate-logical-operands, no-duplicate-if-branches, no-loop-iterable-mutation, and the core no-unassigned-vars); their config comments flag them for a focused audit. Changes the bump requires directly: 1. Port the repo's custom eslint rules to the v10 context API; context.getSourceCode() was removed in favour of context.sourceCode. 2. eslint 10 drops Node.js 18, so .nvmrc moves to 22. 3. Rename getRunInChildContextSubtype and drop an unnecessary String.raw to satisfy the two rules kept on (consistent-compound-words, prefer-string-raw). 4. Remove stale unicorn/no-array-for-each disable directives; the rule was renamed to no-for-each, which is deactivated here. * chore: deduplicate yarn.lock * Apply suggestion from @BridgeAR * test(llmobs): use installed OpenAI fixture version The message extraction tests referenced a helper that does not exist, so lint failed before the versioned provider fixture could load. * ci(lint): update validation code for unicorn v68 The validation code landed after the branch's previous base, so Unicorn 68's new checks only surfaced once the branch was rebased. * chore(lint): use Array.at for latest Cypress screenshot handler * test(cypress): cover latest manual screenshot handler * ci(licenses): include deduplicated vendor dependencies npm list represents hoisted transitive packages without a resolved URL. Skipping those entries makes the local license gate report valid attributions as extraneous when the root dependency graph no longer supplies the same package. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: dd-octo-sts[bot] <200755185+dd-octo-sts[bot]@users.noreply.github.com>
Summary
Updates ESLint from v9 to v10 and eslint-plugin-unicorn from v64 to v68, replacing eslint-plugin-import with eslint-plugin-import-x.
Ports the custom rules and validation scripts to the updated APIs while keeping new recommended rules disabled until each one is audited against supported Node versions, hot paths, and existing code.
Replaces split-then-index autofixes with a single-segment scanner measured 20-56% faster on Node 24.15, and keeps Fastify's no-subscriber hook path allocation-free.
Adds coverage for the affected AI, WebSocket, OracleDB, and Cypress branches, and makes license validation include hoisted vendor dependencies when npm omits their resolved URL.