// Simple TOML parser for shop.toml // Supports basic TOML features needed for the module system function parse_toml(text) { var lines = text.split('\n') var result = {} var current_section = result var current_section_name = '' for (var i = 0; i < lines.length; i++) { var line = lines[i].trim() // Skip empty lines and comments if (!line || line.startsWith('#')) continue // Section header if (line.startsWith('[') && line.endsWith(']')) { var section_path = line.slice(1, -1).split('.') current_section = result current_section_name = section_path.join('.') for (var j = 0; j < section_path.length; j++) { var key = section_path[j] if (!current_section[key]) { current_section[key] = {} } current_section = current_section[key] } continue } // Key-value pair var eq_index = line.indexOf('=') if (eq_index > 0) { var key = line.substring(0, eq_index).trim() var value = line.substring(eq_index + 1).trim() // Parse value if (value.startsWith('"') && value.endsWith('"')) { // String - unescape quotes current_section[key] = value.slice(1, -1).replace(/\\"/g, '"') } else if (value.startsWith('[') && value.endsWith(']')) { // Array current_section[key] = parse_array(value) } else if (value == 'true' || value == 'false') { // Boolean current_section[key] = value == 'true' } else if (!isNaN(Number(value))) { // Number current_section[key] = Number(value) } else { // Unquoted string current_section[key] = value } } } return result } function parse_array(str) { // Remove brackets str = str.slice(1, -1).trim() if (!str) return [] var items = [] var current = '' var in_quotes = false for (var i = 0; i < str.length; i++) { var char = str[i] if (char == '"' && (i == 0 || str[i-1] != '\\')) { in_quotes = !in_quotes current += char } else if (char == ',' && !in_quotes) { items.push(parse_value(current.trim())) current = '' } else { current += char } } if (current.trim()) { items.push(parse_value(current.trim())) } return items } function parse_value(str) { if (str.startsWith('"') && str.endsWith('"')) { return str.slice(1, -1).replace(/\\"/g, '"') } else if (str == 'true' || str == 'false') { return str == 'true' } else if (!isNaN(Number(str))) { return Number(str) } else { return str } } function encode_toml(obj) { var result = [] function encode_value(value) { if (typeof value == 'string') { return '"' + value.replace(/"/g, '\\"') + '"' } else if (typeof value == 'boolean') { return value ? 'true' : 'false' } else if (typeof value == 'number') { return String(value) } else if (Array.isArray(value)) { var items = [] for (var i = 0; i < value.length; i++) { items.push(encode_value(value[i])) } return '[' + items.join(', ') + ']' } return String(value) } // First pass: encode top-level simple values var keys = Object.keys(obj) for (var i = 0; i < keys.length; i++) { var key = keys[i] var value = obj[key] if (value == null || typeof value != 'object' || Array.isArray(value)) { result.push(key + ' = ' + encode_value(value)) } } // Second pass: encode nested objects function encode_section(obj, path) { var keys = Object.keys(obj) for (var i = 0; i < keys.length; i++) { var key = keys[i] var value = obj[key] if (value != null && typeof value == 'object' && !Array.isArray(value)) { // Nested object - create section var section_path = path ? path + '.' + key : key result.push('[' + section_path + ']') // First encode direct properties of this section var section_keys = Object.keys(value) for (var j = 0; j < section_keys.length; j++) { var sk = section_keys[j] var sv = value[sk] if (sv == null || typeof sv != 'object' || Array.isArray(sv)) { result.push(sk + ' = ' + encode_value(sv)) } } // Then encode nested sections encode_section(value, section_path) } } } encode_section(obj, '') return result.join('\n') } return { decode: parse_toml, encode: encode_toml }