Files
cell/scripts/shop.cm

286 lines
7.4 KiB
Plaintext

// Module shop system for managing dependencies and mods
var io = use('io')
var toml = use('toml')
var json = use('json')
var Shop = {}
// Load shop.toml configuration
Shop.load_config = function() {
var shop_path = '.cell/shop.toml'
if (!io.exists(shop_path)) {
return null
}
var content = io.slurp(shop_path)
return toml.parse(content)
}
// Save shop.toml configuration
Shop.save_config = function(config) {
// Simple TOML writer for our needs
var lines = []
// Top-level strings
if (config.module) lines.push('module = "' + config.module + '"')
if (config.engine) lines.push('engine = "' + config.engine + '"')
if (config.entrypoint) lines.push('entrypoint = "' + config.entrypoint + '"')
// Dependencies section
if (config.dependencies && Object.keys(config.dependencies).length > 0) {
lines.push('')
lines.push('[dependencies]')
for (var key in config.dependencies) {
lines.push(key + ' = "' + config.dependencies[key] + '"')
}
}
// Aliases section
if (config.aliases && Object.keys(config.aliases).length > 0) {
lines.push('')
lines.push('[aliases]')
for (var key in config.aliases) {
lines.push(key + ' = "' + config.aliases[key] + '"')
}
}
// Replace section
if (config.replace && Object.keys(config.replace).length > 0) {
lines.push('')
lines.push('[replace]')
for (var key in config.replace) {
lines.push('"' + key + '" = "' + config.replace[key] + '"')
}
}
// Patches section
if (config.patches && Object.keys(config.patches).length > 0) {
lines.push('')
lines.push('[patches]')
for (var key in config.patches) {
lines.push(key + ' = "' + config.patches[key] + '"')
}
}
// Mods section
if (config.mods && config.mods.enabled && config.mods.enabled.length > 0) {
lines.push('')
lines.push('[mods]')
lines.push('enabled = [')
for (var i = 0; i < config.mods.enabled.length; i++) {
lines.push(' "' + config.mods.enabled[i] + '",')
}
lines.push(']')
}
io.slurpwrite('.cell/shop.toml', lines.join('\n'))
}
// Initialize .cell directory structure
Shop.init = function() {
if (!io.exists('.cell')) {
io.mkdir('.cell')
}
if (!io.exists('.cell/modules')) {
io.mkdir('.cell/modules')
}
if (!io.exists('.cell/build')) {
io.mkdir('.cell/build')
}
if (!io.exists('.cell/patches')) {
io.mkdir('.cell/patches')
}
if (!io.exists('.cell/shop.toml')) {
var default_config = {
module: "my-game",
engine: "mist/prosperon@v0.9.3",
entrypoint: "main.js",
dependencies: {},
aliases: {},
replace: {},
patches: {},
mods: {
enabled: []
}
}
Shop.save_config(default_config)
}
if (!io.exists('.cell/lock.toml')) {
io.slurpwrite('.cell/lock.toml', '# Lock file for module integrity\n')
}
return true
}
// Mount modules according to the specification
Shop.mount = function() {
var config = Shop.load_config()
if (!config) {
log.error("No shop.toml found")
return false
}
// 1. Mount mods first (highest priority, prepend=1)
if (config.mods && config.mods.enabled) {
for (var i = 0; i < config.mods.enabled.length; i++) {
var mod_path = config.mods.enabled[i]
if (io.exists(mod_path)) {
io.mount(mod_path, "/", true) // prepend=true
log.console("Mounted mod: " + mod_path)
}
}
}
// 2. Self is already mounted (project root)
// This happens in prosperon.c
// 3. Mount aliases (dependencies)
if (config.dependencies) {
for (var alias in config.dependencies) {
var version = config.dependencies[alias]
var parsed = Shop.parse_locator(version)
var module_name = alias
if (parsed && parsed.version) {
module_name = alias + '@' + parsed.version
}
// Check if replaced with local path
var mount_path = '.cell/modules/' + module_name
if (config.replace && config.replace[version]) {
mount_path = config.replace[version]
}
// Try compiled version first
var compiled_path = '.cell/build/' + module_name
if (io.exists(compiled_path)) {
io.mount(compiled_path, alias, false) // Mount at alias name
log.console("Mounted compiled: " + alias + " at /" + alias + " from " + compiled_path)
} else if (io.exists(mount_path)) {
io.mount(mount_path, alias, false) // Mount at alias name
log.console("Mounted source: " + alias + " at /" + alias + " from " + mount_path)
}
// Also handle short aliases
if (config.aliases) {
for (var short_alias in config.aliases) {
if (config.aliases[short_alias] === alias) {
if (io.exists(compiled_path)) {
io.mount(compiled_path, short_alias, false)
log.console("Mounted alias: " + short_alias + " -> " + alias)
} else if (io.exists(mount_path)) {
io.mount(mount_path, short_alias, false)
log.console("Mounted alias: " + short_alias + " -> " + alias)
}
}
}
}
}
}
// 4. Mount compiled modules directory
if (io.exists('.cell/build')) {
io.mount('.cell/build', "modules", false)
log.console("Mounted compiled modules at /modules")
}
// 5. Mount source modules directory
if (io.exists('.cell/modules')) {
io.mount('.cell/modules', "modules-src", false)
log.console("Mounted source modules at /modules-src")
}
// 6. Mount core if available
if (io.exists('.cell/modules/core')) {
io.mount('.cell/modules/core', "core", false)
log.console("Mounted core at /core")
}
// 6. Core is already mounted in prosperon.c
return true
}
// Parse module locator (e.g., "git.world/jj/mod@v0.6.3")
Shop.parse_locator = function(locator) {
var parts = locator.split('@')
if (parts.length !== 2) {
return null
}
return {
path: parts[0],
version: parts[1],
name: parts[0].split('/').pop()
}
}
// Add a dependency
Shop.add_dependency = function(alias, locator) {
var config = Shop.load_config()
if (!config) {
log.error("No shop.toml found")
return false
}
if (!config.dependencies) {
config.dependencies = {}
}
config.dependencies[alias] = locator
Shop.save_config(config)
return true
}
// Get the module directory for a given alias
Shop.get_module_dir = function(alias) {
var config = Shop.load_config()
if (!config || !config.dependencies || !config.dependencies[alias]) {
return null
}
var version = config.dependencies[alias]
var module_name = alias + '@' + version.split('@')[1]
// Check if replaced
if (config.replace && config.replace[version]) {
return config.replace[version]
}
return '.cell/modules/' + module_name
}
// Compile a module
Shop.compile_module = function(alias) {
var module_dir = Shop.get_module_dir(alias)
if (!module_dir) {
log.error("Module not found: " + alias)
return false
}
// TODO: Implement actual compilation
// For now, just copy .js files to .cell/build with .o extension
log.console("Would compile module: " + alias + " from " + module_dir)
return true
}
// Build all modules
Shop.build = function() {
var config = Shop.load_config()
if (!config || !config.dependencies) {
return true
}
for (var alias in config.dependencies) {
Shop.compile_module(alias)
}
return true
}
return Shop