Module: Klenod::Runtime::BundleFormat
- Defined in:
- lib/klenod/runtime/bundle_format.rb
Constant Summary collapse
- MAGIC =
"MODPACK_BUNDLE_V1\n"- FORMAT_VERSION =
1
Class Method Summary collapse
- .bundle_from_payload(payload, source_root: nil) ⇒ Object
- .decode_assets(payload) ⇒ Object
- .decode_import(payload) ⇒ Object
- .decode_imports(payload) ⇒ Object
- .decode_modules(payload) ⇒ Object
- .decode_source_map(payload, output) ⇒ Object
- .decode_value(value) ⇒ Object
- .dump(bundle) ⇒ Object
- .encode_assets(assets) ⇒ Object
- .encode_import(import) ⇒ Object
- .encode_imports(imports) ⇒ Object
- .encode_modules(modules) ⇒ Object
- .encode_source_map(source_map) ⇒ Object
- .encode_value(value) ⇒ Object
- .expect_hash!(value, label) ⇒ Object
- .load(source, source_root: nil) ⇒ Object
- .load_bytes(bytes, source_root: nil) ⇒ Object
- .payload_for(bundle) ⇒ Object
- .read_source(source) ⇒ Object
- .validate_payload!(payload) ⇒ Object
Class Method Details
.bundle_from_payload(payload, source_root: nil) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/klenod/runtime/bundle_format.rb', line 48 def bundle_from_payload(payload, source_root: nil) validate_payload!(payload) bundle = Bundle.new( decode_value(payload.fetch("entrypoints")), decode_modules(payload.fetch("modules")), decode_assets(payload.fetch("assets")), source_root: decode_value(payload["source_root"]) ) bundle.source_root = source_root if source_root bundle end |
.decode_assets(payload) ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/klenod/runtime/bundle_format.rb', line 166 def decode_assets(payload) expect_hash!(payload, "assets").to_h do |output_path, asset_payload| asset_payload = expect_hash!(asset_payload, "asset #{output_path}") [ output_path, AssetSpec.new( asset_payload.fetch("logical_name"), asset_payload.fetch("content_hash"), asset_payload.fetch("output_path"), asset_payload.fetch("content_type"), decode_value(asset_payload.fetch("metadata")) ) ] end end |
.decode_import(payload) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/klenod/runtime/bundle_format.rb', line 139 def decode_import(payload) payload = expect_hash!(payload, "import") case payload.fetch("type") when "import_spec" ImportSpec.new(payload.fetch("target_id"), decode_value(payload["value"]), payload.fetch("eager")) when "module_id" payload.fetch("target_id") else raise BundleFormatError, "Unknown import type: #{payload["type"].inspect}" end end |
.decode_imports(payload) ⇒ Object
118 119 120 |
# File 'lib/klenod/runtime/bundle_format.rb', line 118 def decode_imports(payload) expect_hash!(payload, "imports").to_h { |name, import| [name, decode_import(import)] } end |
.decode_modules(payload) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/klenod/runtime/bundle_format.rb', line 96 def decode_modules(payload) expect_hash!(payload, "modules").to_h do |id, spec_payload| spec_payload = expect_hash!(spec_payload, "module #{id}") [ id, ModuleSpec.new( spec_payload.fetch("id"), spec_payload.fetch("source_path"), spec_payload.fetch("source"), decode_imports(spec_payload.fetch("imports")), decode_source_map(spec_payload["source_map"], spec_payload.fetch("source")), spec_payload.fetch("version"), spec_payload.fetch("constant_name") ) ] end end |
.decode_source_map(payload, output) ⇒ Object
194 195 196 197 198 199 200 201 202 203 |
# File 'lib/klenod/runtime/bundle_format.rb', line 194 def decode_source_map(payload, output) return nil unless payload payload = expect_hash!(payload, "source map") marks = expect_hash!(payload.fetch("marks_by_output_line"), "source map marks").to_h do |line, source_line| [line.to_i, SourceMap::Mark.new(source_line)] end SourceMap::SourceMap.new(payload.fetch("input"), output, marks.freeze) end |
.decode_value(value) ⇒ Object
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/klenod/runtime/bundle_format.rb', line 228 def decode_value(value) case value when nil, true, false, String, Integer, Float value when Array value.map { |item| decode_value(item) } when Hash case value["__klenod_type"] when "symbol" value.fetch("value").to_sym when "hash" value.fetch("entries").to_h do |key, hash_value| [decode_value(key), decode_value(hash_value)] end when "default_import" DefaultImport.new(value.fetch("name").to_sym) else value.to_h { |key, hash_value| [key, decode_value(hash_value)] } end else raise BundleFormatError, "Cannot decode bundle value: #{value.class}" end end |
.dump(bundle) ⇒ Object
19 20 21 |
# File 'lib/klenod/runtime/bundle_format.rb', line 19 def dump(bundle) MAGIC + JSON.generate(payload_for(bundle)) end |
.encode_assets(assets) ⇒ Object
151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/klenod/runtime/bundle_format.rb', line 151 def encode_assets(assets) assets.to_h do |output_path, asset| [ output_path.to_s, { "logical_name" => asset.logical_name, "content_hash" => asset.content_hash, "output_path" => asset.output_path, "content_type" => asset.content_type, "metadata" => encode_value(asset.) } ] end end |
.encode_import(import) ⇒ Object
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/klenod/runtime/bundle_format.rb', line 122 def encode_import(import) case import when ImportSpec { "type" => "import_spec", "target_id" => import.target_id, "value" => encode_value(import.value), "eager" => import.eager } else { "type" => "module_id", "target_id" => import.to_s } end end |
.encode_imports(imports) ⇒ Object
114 115 116 |
# File 'lib/klenod/runtime/bundle_format.rb', line 114 def encode_imports(imports) imports.to_h { |name, import| [name.to_s, encode_import(import)] } end |
.encode_modules(modules) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/klenod/runtime/bundle_format.rb', line 79 def encode_modules(modules) modules.to_h do |id, spec| [ id.to_s, { "id" => spec.id, "source_path" => spec.source_path, "source" => spec.source, "imports" => encode_imports(spec.imports), "source_map" => encode_source_map(spec.source_map), "version" => spec.version, "constant_name" => spec.constant_name } ] end end |
.encode_source_map(source_map) ⇒ Object
182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/klenod/runtime/bundle_format.rb', line 182 def encode_source_map(source_map) return nil unless source_map { "input" => source_map.input, "marks_by_output_line" => source_map.marks_by_output_line.to_h do |line, mark| [line.to_s, mark.line] end } end |
.encode_value(value) ⇒ Object
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/klenod/runtime/bundle_format.rb', line 205 def encode_value(value) case value when nil, true, false, String, Integer, Float value when Symbol {"__klenod_type" => "symbol", "value" => value.to_s} when Array value.map { |item| encode_value(item) } when Hash { "__klenod_type" => "hash", "entries" => value.map do |key, hash_value| [encode_value(key), encode_value(hash_value)] end } when DefaultImport {"__klenod_type" => "default_import", "name" => value.name.to_s} else raise BundleFormatError, "Cannot encode bundle value: #{value.class}" end end |
.expect_hash!(value, label) ⇒ Object
252 253 254 255 256 |
# File 'lib/klenod/runtime/bundle_format.rb', line 252 def expect_hash!(value, label) return value if value.is_a?(Hash) raise BundleFormatError, "Malformed Klenod bundle payload: #{label} must be an object" end |
.load(source, source_root: nil) ⇒ Object
23 24 25 |
# File 'lib/klenod/runtime/bundle_format.rb', line 23 def load(source, source_root: nil) load_bytes(read_source(source), source_root: source_root) end |
.load_bytes(bytes, source_root: nil) ⇒ Object
27 28 29 30 31 32 33 34 35 |
# File 'lib/klenod/runtime/bundle_format.rb', line 27 def load_bytes(bytes, source_root: nil) raise BundleFormatError, "Invalid Klenod bundle header" unless bytes.start_with?(MAGIC) body = bytes.byteslice(MAGIC.bytesize, bytes.bytesize - MAGIC.bytesize) payload = JSON.parse(body) bundle_from_payload(payload, source_root: source_root) rescue JSON::ParserError => error raise BundleFormatError, "Invalid Klenod bundle JSON: #{error.}" end |
.payload_for(bundle) ⇒ Object
37 38 39 40 41 42 43 44 45 46 |
# File 'lib/klenod/runtime/bundle_format.rb', line 37 def payload_for(bundle) { "format_version" => FORMAT_VERSION, "runtime_version" => Runtime::VERSION, "source_root" => encode_value(bundle.source_root), "entrypoints" => encode_value(bundle.entrypoints), "modules" => encode_modules(bundle.modules), "assets" => encode_assets(bundle.assets) } end |
.read_source(source) ⇒ Object
62 63 64 |
# File 'lib/klenod/runtime/bundle_format.rb', line 62 def read_source(source) source.respond_to?(:read) ? source.read : File.binread(source) end |
.validate_payload!(payload) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/klenod/runtime/bundle_format.rb', line 66 def validate_payload!(payload) raise BundleFormatError, "Malformed Klenod bundle payload" unless payload.is_a?(Hash) version = payload["format_version"] unless version == FORMAT_VERSION raise BundleFormatError, "Unsupported Klenod bundle format version: #{version.inspect}" end %w[runtime_version source_root entrypoints modules assets].each do |key| raise BundleFormatError, "Malformed Klenod bundle payload: missing #{key}" unless payload.key?(key) end end |