Module: Esp::Mw::Loader

Defined in:
lib/esp/mw/loader.rb

Overview

Loads a mod’s source records from one of the supported formats.

The contract: every loader returns an Array of record hashes shaped for tes3conv. Keys are normalised to strings so downstream code (preflight, builder) doesn’t have to care which format the source was authored in.

Supported source files (per mod folder, exactly one):

mods/<Mod>/<Mod>.json   — straight JSON
mods/<Mod>/<Mod>.rb     — Ruby file; last expression is the Array
mods/<Mod>/<Mod>.py     — Python script; prints JSON Array to stdout
mods/<Mod>/<Mod>.js     — Node script; same contract
mods/<Mod>/<Mod>.mjs    — Node ES module; same contract
mods/<Mod>/<Mod>.ts     — Deno TypeScript; same contract

For subprocess loaders (py/js/mjs/ts) the interpreter runs with cwd set to the mod’s source directory, so relative file reads from the script just work. The script’s own path is passed as the last arg.

Defined Under Namespace

Classes: LoadError

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.interpretersObject

Extension -> command vector. Mutable so tests / local config can poke at it without freeze/unfreeze dances.



30
31
32
# File 'lib/esp/mw/loader.rb', line 30

def interpreters
  @interpreters
end

Class Method Details

.load(path, i18n: nil) ⇒ Object

Raises:



52
53
54
55
56
57
58
59
60
61
# File 'lib/esp/mw/loader.rb', line 52

def load(path, i18n: nil)
  raise LoadError, Esp.t('errors.loader.not_found', path: path) unless File.exist?(path)

  records = dispatch(path, i18n)
  unless records.is_a?(Array)
    raise LoadError, Esp.t('errors.loader.not_array', path: path, klass: records.class)
  end

  records.map { |r| stringify_keys(r) }
end

.resolve(mod, root: Esp::ROOT) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/esp/mw/loader.rb', line 36

def resolve(mod, root: Esp::ROOT)
  candidates = supported_exts
               .map { |ext| File.join(root, 'mods', mod, "#{mod}#{ext}") }
               .select { |p| File.exist?(p) }
  if candidates.empty?
    wanted = supported_exts.map { |e| "#{mod}#{e}" }.join(', ')
    raise LoadError, Esp.t('errors.loader.no_source', mod: mod.inspect, exts: wanted)
  end
  if candidates.size > 1
    names = candidates.map { |c| File.basename(c) }.join(', ')
    raise LoadError, Esp.t('errors.loader.multiple_sources', mod: mod.inspect, names: names)
  end

  candidates.first
end

.supported_extsObject



32
33
34
# File 'lib/esp/mw/loader.rb', line 32

def supported_exts
  %w[.rb .json] + interpreters.keys
end