171 lines
3.9 KiB
Lua
171 lines
3.9 KiB
Lua
-- modules/json.lua - High-performance JSON module using Go functions
|
|
|
|
local json = {}
|
|
|
|
-- Use the fast Go JSON encoder/decoder
|
|
function json.encode(value)
|
|
return moonshark.json_encode(value)
|
|
end
|
|
|
|
function json.decode(str)
|
|
local result, err = moonshark.json_decode(str)
|
|
if result == nil and err then
|
|
error("json_decode: " .. err)
|
|
end
|
|
return result
|
|
end
|
|
|
|
-- Pretty print JSON with indentation
|
|
function json.pretty(value, indent)
|
|
indent = indent or 2
|
|
local encoded = json.encode(value)
|
|
local result = {}
|
|
local depth = 0
|
|
local in_string = false
|
|
local escape_next = false
|
|
|
|
for i = 1, #encoded do
|
|
local char = encoded:sub(i, i)
|
|
|
|
if escape_next then
|
|
table.insert(result, char)
|
|
escape_next = false
|
|
elseif char == "\\" and in_string then
|
|
table.insert(result, char)
|
|
escape_next = true
|
|
elseif char == '"' then
|
|
table.insert(result, char)
|
|
in_string = not in_string
|
|
elseif not in_string then
|
|
if char == "{" or char == "[" then
|
|
table.insert(result, char)
|
|
depth = depth + 1
|
|
table.insert(result, "\n" .. string.rep(" ", depth * indent))
|
|
elseif char == "}" or char == "]" then
|
|
depth = depth - 1
|
|
table.insert(result, "\n" .. string.rep(" ", depth * indent))
|
|
table.insert(result, char)
|
|
elseif char == "," then
|
|
table.insert(result, char)
|
|
table.insert(result, "\n" .. string.rep(" ", depth * indent))
|
|
elseif char == ":" then
|
|
table.insert(result, char .. " ")
|
|
else
|
|
table.insert(result, char)
|
|
end
|
|
else
|
|
table.insert(result, char)
|
|
end
|
|
end
|
|
|
|
return table.concat(result)
|
|
end
|
|
|
|
-- Load JSON from file
|
|
function json.load_file(filename)
|
|
if not moonshark.file_exists(filename) then
|
|
error("File not found: " .. filename)
|
|
end
|
|
|
|
local file = io.open(filename, "r")
|
|
if not file then
|
|
error("Cannot open file: " .. filename)
|
|
end
|
|
|
|
local content = file:read("*all")
|
|
file:close()
|
|
|
|
return json.decode(content)
|
|
end
|
|
|
|
-- Save data to JSON file
|
|
function json.save_file(filename, data, pretty)
|
|
local content
|
|
if pretty then
|
|
content = json.pretty(data)
|
|
else
|
|
content = json.encode(data)
|
|
end
|
|
|
|
local file = io.open(filename, "w")
|
|
if not file then
|
|
error("Cannot write to file: " .. filename)
|
|
end
|
|
|
|
file:write(content)
|
|
file:close()
|
|
end
|
|
|
|
-- Merge JSON objects
|
|
function json.merge(...)
|
|
local result = {}
|
|
for i = 1, select("#", ...) do
|
|
local obj = select(i, ...)
|
|
if type(obj) == "table" then
|
|
for k, v in pairs(obj) do
|
|
result[k] = v
|
|
end
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
-- Extract values by JSONPath-like syntax (simplified)
|
|
function json.extract(data, path)
|
|
local parts = moonshark.string_split(path, ".")
|
|
local current = data
|
|
|
|
for _, part in ipairs(parts) do
|
|
if type(current) ~= "table" then
|
|
return nil
|
|
end
|
|
|
|
-- Handle array indices [0], [1], etc.
|
|
local array_match = part:match("^%[(%d+)%]$")
|
|
if array_match then
|
|
local index = tonumber(array_match) + 1 -- Lua is 1-indexed
|
|
current = current[index]
|
|
else
|
|
current = current[part]
|
|
end
|
|
|
|
if current == nil then
|
|
return nil
|
|
end
|
|
end
|
|
|
|
return current
|
|
end
|
|
|
|
-- Validate JSON structure against schema (basic)
|
|
function json.validate(data, schema)
|
|
local function validate_value(value, schema_value)
|
|
local value_type = type(value)
|
|
local schema_type = schema_value.type
|
|
|
|
if schema_type and value_type ~= schema_type then
|
|
return false, "Expected " .. schema_type .. ", got " .. value_type
|
|
end
|
|
|
|
if schema_type == "table" and schema_value.properties then
|
|
for prop, prop_schema in pairs(schema_value.properties) do
|
|
if schema_value.required and schema_value.required[prop] and value[prop] == nil then
|
|
return false, "Missing required property: " .. prop
|
|
end
|
|
|
|
if value[prop] ~= nil then
|
|
local valid, err = validate_value(value[prop], prop_schema)
|
|
if not valid then
|
|
return false, "Property " .. prop .. ": " .. err
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
return validate_value(data, schema)
|
|
end
|
|
|
|
return json |