UtopiaSourceUtopiaImportMapBuilder

class Builder

Builder class for constructing import maps with scoped base URIs.

The builder supports nested with(base:) blocks where each base is resolved relative to its parent base, following RFC 3986 URL resolution rules.

Example: Nested base resolution.

ImportMap.build do |map|
	# No base - imports as-is
	map.import("app", "/app.js")
	
	# Base: "https://cdn.example.com/"
	map.with(base: "https://cdn.example.com/") do |cdn|
		cdn.import("lib", "lib.js")  # => "https://cdn.example.com/lib.js"
		
		# Nested base: "https://cdn.example.com/" + "v2/" = "https://cdn.example.com/v2/"
		cdn.with(base: "v2/") do |v2|
			v2.import("new-lib", "lib.js")  # => "https://cdn.example.com/v2/lib.js"
		end
	end
end

Signature

Definitions

def import(specifier, value, integrity: nil)

Add an import mapping with the current base URI.

If a base is set, the value is resolved relative to that base following RFC 3986. Absolute URLs (scheme://...) are preserved as-is when used as values.

Example: With base URL.

builder = Builder.new(map, base: "https://cdn.com/")
builder.import("lib", "lib.js")  # Resolves to: "https://cdn.com/lib.js"
builder.import("ext", "https://other.com/ext.js")  # Keeps: "https://other.com/ext.js"

Signature

parameter specifier String

The module specifier (e.g., "react", "@myapp/utils").

parameter value String

The URL or path to resolve to.

parameter integrity String, nil

Optional subresource integrity hash.

returns Builder

Self for method chaining.

Implementation

def import(specifier, value, integrity: nil)
	resolved_value = if @base
		value_url = Protocol::URL[value]
		
		# Combine base with value
		(@base + value_url).to_s
	else
		value
	end
	
	@import_map.import(specifier, resolved_value, integrity: integrity)
	
	self
end

def with(base:, &block)

Create a nested scope with a different base URI.

The new base is resolved relative to the current base. This allows for hierarchical organization of imports from different sources.

Example: Nested CDN paths.

builder.with(base: "https://cdn.com/") do |cdn|
	cdn.with(base: "libs/v2/") do |v2|
		# Base is now: "https://cdn.com/libs/v2/"
		v2.import("util", "util.js")  # => "https://cdn.com/libs/v2/util.js"
	end
end

Signature

parameter base String

The new base URI, resolved relative to current base.

returns Builder

The builder instance.

Implementation

def with(base:, &block)
	# Resolve the new base relative to the current base
	resolved_base = if @base
		@base + Protocol::URL[base]
	else
		base
	end
	
	self.class.build(@import_map, base: resolved_base, &block)
end

def scope(scope_prefix, imports)

Add a scope mapping.

Scopes allow different import resolutions for different parts of your application.

Example: Scope-specific imports.

builder.scope("/admin/", {"utils" => "/admin/utils.js"})

Signature

parameter scope_prefix String

The scope prefix (e.g., "/pages/").

parameter imports Hash

Import mappings specific to this scope.

returns Builder

Self for method chaining.

Implementation

def scope(scope_prefix, imports)
	@import_map.scope(scope_prefix, imports)
	self
end