Class: Utopia::ImportMap::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/utopia/import_map.rb

Overview

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.

Examples:

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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(import_map, base: nil) ⇒ Builder

Initialize a scoped builder for an import map.



99
100
101
102
# File 'lib/utopia/import_map.rb', line 99

def initialize(import_map, base: nil)
	@import_map = import_map
	@base = Protocol::URL[base]
end

Class Method Details

.build(import_map, **options, &block) ⇒ Object

Configure an import map using a scoped builder.



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/utopia/import_map.rb', line 84

def self.build(import_map, **options, &block)
	builder = self.new(import_map, **options)
	
	if block.arity == 1
		yield(builder)
	else
		builder.instance_eval(&block)
	end
	
	return builder
end

Instance Method Details

#import(specifier, value, integrity: nil) ⇒ Object

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.

Examples:

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"


118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/utopia/import_map.rb', line 118

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

#scope(scope_prefix, imports) ⇒ Object

Add a scope mapping.

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

Examples:

Scope-specific imports.

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


170
171
172
173
# File 'lib/utopia/import_map.rb', line 170

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

#with(base:, &block) ⇒ Object

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.

Examples:

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


149
150
151
152
153
154
155
156
157
158
# File 'lib/utopia/import_map.rb', line 149

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