Skip to content

fix(cli): pin --vendor leaves a pin to a custom URL alone - #41

Merged
mhenrixon merged 2 commits into
mainfrom
fix/vendor-keeps-custom-url
Sep 19, 2026
Merged

mhenrixon merged 2 commits into
mainfrom
fix/vendor-keeps-custom-url

Conversation

@mhenrixon

@mhenrixon mhenrixon commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

bin/importmap pin <pkg> --vendor against a pin whose to: is a host no provider answers for discarded the URL without a word and vendored the file from whichever CDN the spec resolved to.

pin "md5", to: "https://cdn.example.com/md5.js", preload: false

$ bin/importmap pin md5@2.3.0 --vendor
Pinning "md5" to vendor/javascript/md5.js via download from https://ga.jspm.io/npm:md5@2.3.0/md5.js

Commands#pin_package reaches repin_remote_package — the only place that prints Skipping "…" pinned to custom URL … — only when existing_url && !vendor && !regraph. With --vendor that branch is skipped, --remote is false, and control falls to pin_vendored_package. vendor ||= packager.vendored?(package) then kept the pin that way on every later rewrite.

The fix is one elsif in pin_package plus the sentence it prints:

elsif existing_url && from.nil? && packager.provider_for_url(existing_url).nil?
  keep_custom_url(package, existing_url)
$ bin/importmap pin md5@2.3.0 --vendor
Skipping "md5" pinned to custom URL https://cdn.example.com/md5.js (--vendor doesn't move a pin to another source; pass --from to choose one)

Docs updated: docs/app/views/docs/pages/pinning.rb (Custom URLs now shows the --vendor skip and points at --from), docs/app/views/docs/pages/multi_file_packages.rb (the paragraph that already said --vendor "only overrides a check" now says what that means for a custom URL).
CHANGELOG entry under ## 1.2.0### Fixed.

Closes #29

Test plan

  • bundle exec rake test — 433 runs, 0 failures, with bun installed
  • New test seen RED first: on main it fails with Pinning "md5" to vendor/javascript/md5.js via download from https://ga.jspm.io/… where the skip was expected
  • cd docs && bundle exec rake lint && bundle exec rspec — 53 files no offenses, 54 examples passed (the internal-links spec covers the new #custom-urls link)
  • Manual: pin "md5", to: "https://cdn.example.com/md5.js" in an app, then bin/importmap pin md5 --vendor — line unchanged, nothing in vendor/javascript; bin/importmap pin md5 --vendor --from jspm — vendored

Deviations & judgment calls

  • The issue offered two outcomes; this takes the "refuse with a sentence" one. Vendoring from the custom URL was the other option. Rejected because --vendor's documented job is overriding the single-file check, not choosing a source, and because a custom URL carries no version and no provider — vendored_pin_for would have to invent a provenance comment shape (# @? with no CDN) that nothing else in the pin-line contract produces. That is a feature with a design of its own, not this bug's fix. The bug here is the silence, and the silence is what this removes. Happy to open a follow-up issue for "vendor the file the app actually pinned" if you want it.
  • --from stands the guard down. repin_remote_package already returns early on from, so pin md5 --from jspm moves a custom-URL pin today. Making --vendor refuse unconditionally would have left --vendor --from jspm refusing where --from jspm alone works. A second test pins that behaviour down so the escape hatch can't rot.
  • It prints and carries on rather than calling skip(). skip() makes pin exit 1; the existing custom-URL path just puts and exits 0. Matching the sibling was worth more than flagging it as a failure, and run_importmap_command would have flunked on a non-zero exit anyway.
  • A live commands_test.rb case is justified here under .claude/rules/testing.md: this is a new printed sentence, which is one of the two things that earns a live test. Versions are pinned (md5@2.3.0, md5@2.2.0) so a new md5 release can't move the expectations.
  • Tests appended at the end of commands_test.rb, not next to their sibling at line 214, per the upstream-sync rule that keeps the merge cheap.
  • Stacked on nothing. This branches off main independently of fix(cli): read an array preload back whatever quotes it is written in #40 (issue Single-quoted array preload crashes extract_existing_pin_options; empty array is dropped #28); the two diffs don't overlap.

Summary by cubic

Fixes #29 so bin/importmap pin --vendor leaves a pin to a custom URL alone. Previously it silently replaced the pinned URL by vendoring from whichever CDN the spec resolved to; now it prints a skip message naming --from and leaves importmap.rb and vendor/javascript untouched.

  • --vendor --from <cdn> still vendors from the named CDN.
  • Updates the pinning and multi-file package docs, plus the CHANGELOG.

Written for commit a53fb16. Summary will update on new commits.

Review in cubic

--vendor overrides the check that refuses a download; it does not name a
destination. The docs already say so in as many words — "--remote wins; it
names a destination, where --vendor only overrides a check" — but the code
disagreed, because the branch that skips a custom URL runs only while vendor
is false:

  pin "md5", to: "https://cdn.example.com/md5.js", preload: false
  $ bin/importmap pin md5@2.3.0 --vendor
  Pinning "md5" to vendor/javascript/md5.js via download from https://ga.jspm.io/…

The URL the app had chosen was gone, replaced by a file from whichever CDN the
spec happened to resolve to, and `vendor ||= packager.vendored?(package)` kept
it that way on every later rewrite. Nothing was printed about it.

The skip now happens whether or not --vendor was passed, and the sentence
names the flag so the override doesn't look ignored. --from is left as the one
way to move such a pin on purpose: it already overrules a custom URL in
repin_remote_package, so the guard stands down when a CDN was named, and
--vendor --from still vendors from that CDN.

## Test coverage
- test/commands_test.rb: --vendor against a custom-URL pin prints the skip and
  leaves both config/importmap.rb and vendor/javascript untouched; --vendor
  --from jspm still vendors, so the escape hatch is pinned down too

Closes #29
CHANGELOG.md was the only conflict: #40 and this branch each appended a
bullet to 1.2.0's "### Fixed" at the same spot. Union, main's bullet first.
@mhenrixon
mhenrixon merged commit 8b9ab0f into main Sep 19, 2026
47 checks passed
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.

pin --vendor silently discards a custom-URL pin and vendors from the resolved CDN instead

1 participant