Class: Wabi::ZagVendor
- Inherits:
-
Object
- Object
- Wabi::ZagVendor
- Defined in:
- lib/wabi/zag_vendor.rb
Overview
Walks the jsDelivr ‘+esm` import graph for one or more root packages and rewrites cross-package CDN references (`/npm/<pkg>@<ver>/+esm`) to bare specifiers (`<pkg>`), so every file can be served locally and resolved through the importmap (Propshaft-digest-safe). Pure: HTTP is injected via `fetcher`, a callable taking a URL string and returning the body string.
Defined Under Namespace
Classes: Result
Constant Summary collapse
- CDN =
"https://cdn.jsdelivr.net"- REF =
/npm/<pkg>@<ver>/+esm — <pkg> may be scoped (@scope/name). jsDelivr references both the package root (‘@ver/+esm`) and subpath exports (`@ver/dom/+esm`, e.g. @floating-ui/utils/dom); group 3 captures the optional subpath so those resolve to a distinct local module too.
%r{/npm/((?:@[^/]+/)?[^/@]+)@([^/]+?)((?:/[^/]+)*?)/\+esm}
Class Method Summary collapse
Instance Method Summary collapse
-
#call(roots) ⇒ Object
roots: [{ pkg: “@zag-js/dialog”, ver: “1.41.0” }, …].
-
#initialize(fetcher) ⇒ ZagVendor
constructor
A new instance of ZagVendor.
Constructor Details
#initialize(fetcher) ⇒ ZagVendor
Returns a new instance of ZagVendor.
26 27 28 |
# File 'lib/wabi/zag_vendor.rb', line 26 def initialize(fetcher) @fetcher = fetcher end |
Class Method Details
.call(roots, fetcher:) ⇒ Object
22 23 24 |
# File 'lib/wabi/zag_vendor.rb', line 22 def self.call(roots, fetcher:) new(fetcher).call(roots) end |
Instance Method Details
#call(roots) ⇒ Object
roots: [{ pkg: “@zag-js/dialog”, ver: “1.41.0” }, …]
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/wabi/zag_vendor.rb', line 31 def call(roots) files = {} versions = {} # specifier => normalized version (first seen) queue = roots.map { |r| { spec: r[:pkg], sub: "", ver: normalize_version(r[:ver]) } } until queue.empty? item = queue.shift spec = item[:spec] # bare specifier incl. any subpath, e.g. "@floating-ui/utils/dom" pkg = spec.sub(item[:sub], "") # package name without the subpath, for the fetch URL ver = item[:ver] # Dedupe by SPECIFIER (package + subpath), not by URL: jsDelivr's real # graph references the same module both as a resolved pin (`@0.2.11`) and # as a range (`@%5E0.2.11`, i.e. URL-encoded `^0.2.11`). Those normalize # to the same version and the rewrite drops the version anyway (bare # specifier). Only genuinely-different versions (after normalizing the # range/encoding) are a real conflict a single bare importmap pin can't # carry. if versions.key?(spec) if versions[spec] != ver raise Wabi::Error, "vendor: #{spec} appears at two versions (#{versions[spec]} and #{ver}); " \ "a bare importmap pin can't carry two versions" end next end versions[spec] = ver content = @fetcher.call("#{CDN}/npm/#{pkg}@#{ver}#{item[:sub]}/+esm") files[spec] = content.gsub(REF) do dep_pkg = Regexp.last_match(1) dep_ver = normalize_version(Regexp.last_match(2)) dep_sub = Regexp.last_match(3).to_s # "" or "/dom" dep_spec = "#{dep_pkg}#{dep_sub}" queue << { spec: dep_spec, sub: dep_sub, ver: dep_ver } dep_spec end end Result.new(files, versions) end |