diff --git a/lib/utopia/import_map.rb b/lib/utopia/import_map.rb index 6502d0ed..ab52969a 100644 --- a/lib/utopia/import_map.rb +++ b/lib/utopia/import_map.rb @@ -268,13 +268,7 @@ def scope(scope_prefix, imports) # page_map = import_map.relative_to("/foo/bar/") # # Base becomes: "../../_components/" def relative_to(path) - if @base - # Calculate the relative path from the page to the base - relative_path = @base.path.relative(path) - resolved_base = Protocol::URL::Relative.new(relative_path) - else - resolved_base = nil - end + resolved_base = @base&.relative_to(path) instance = self.class.new(@imports.dup, @integrity.dup, @scopes.dup, base: resolved_base) @@ -285,10 +279,12 @@ def relative_to(path) # # @parameter value [String] The import URL or path value. # @parameter base [Protocol::URL | Nil] The base URL context for resolving relative paths. - # @returns [Protocol::URL | String] The resolved URL object or original string. + # @returns [Protocol::URL] The resolved URL. private def resolve_value(value, base) + value = Protocol::URL[value] + if base - base + Protocol::URL[value] + base + value else value end @@ -303,7 +299,7 @@ def relative_to(path) result = {} imports.each do |specifier, value| - result[specifier] = resolve_value(value, base).to_s + result[specifier] = resolve_value(value, base).to_s(explicit: true) end result diff --git a/test/utopia/import_map.rb b/test/utopia/import_map.rb index ffdce596..0d66355b 100644 --- a/test/utopia/import_map.rb +++ b/test/utopia/import_map.rb @@ -139,6 +139,23 @@ expect(page_map.base.to_s).to be == "../../_components/" end + it "generates explicit same-directory URLs" do + import_map = subject.build(base: "/_components/") do |map| + map.import("app", "./app.js") + end + page_map = import_map.relative_to("/index") + + expect(page_map.base.to_s).to be == "_components/" + expect(page_map.as_json.dig("imports", "app")).to be == "./_components/app.js" + end + + it "preserves absolute bases" do + import_map = subject.new(base: "https://cdn.example.com/components/") + page_map = import_map.relative_to("/index") + + expect(page_map.base.to_s).to be == "https://cdn.example.com/components/" + end + it "accepts a structured page path" do import_map = subject.new(base: "/_components/") path = Protocol::URL::Path["/foo/bar/"] @@ -200,6 +217,14 @@ json = import_map.as_json expect(json["imports"]["components/button"]).to be == "/components/button.js" end + + it "identifies ambiguous relative addresses explicitly" do + import_map = subject.build do |map| + map.import("app", "js/app.js") + end + + expect(import_map.as_json.dig("imports", "app")).to be == "./js/app.js" + end end with "with base" do @@ -242,15 +267,15 @@ it "resolves multiple relative path styles" do json = import_map.as_json - # "pages/blog/" + "./app.js" => "pages/blog/app.js" - expect(json["imports"]["app"]).to be == "pages/blog/app.js" + # Import map addresses must be explicit relative URLs. + expect(json["imports"]["app"]).to be == "./pages/blog/app.js" end it "resolves parent directory references" do json = import_map.as_json - # "pages/blog/" + "../vendor/lib.js" => "pages/vendor/lib.js" - expect(json["imports"]["vendor"]).to be == "pages/vendor/lib.js" + # The resolved address is in the current directory tree. + expect(json["imports"]["vendor"]).to be == "./pages/vendor/lib.js" end it "keeps CDN URLs unchanged" do @@ -403,7 +428,7 @@ expect(json["imports"]["preact"]).to be(:start_with?, "//") # Paths resolved with base - expect(json["imports"]["app"]).to be(:start_with?, "pages") + expect(json["imports"]["app"]).to be(:start_with?, "./pages") end it "supports full import map specification" do diff --git a/utopia.gemspec b/utopia.gemspec index 672dbe5a..cda1c90e 100644 --- a/utopia.gemspec +++ b/utopia.gemspec @@ -36,7 +36,7 @@ Gem::Specification.new do |spec| spec.add_dependency "protocol-http", "~> 0.70" spec.add_dependency "protocol-media", "~> 0.3" spec.add_dependency "protocol-media-registry", "~> 0.1" - spec.add_dependency "protocol-url", "~> 0.16" + spec.add_dependency "protocol-url", "~> 0.18" spec.add_dependency "samovar", "~> 2.1" spec.add_dependency "traces", "~> 0.10" spec.add_dependency "variant", "~> 0.1"