---@param file string json file path
---@param default table default value
---@return boolean isOk, table data, string message
function Json(file, default)
assert(file)
assert(default)
local function fillEmptyKeys(default, current)
local changedValues = 0
for k, v in pairs(default) do
if type(current[k]) == 'nil' then
current[k] = v
changedValues = changedValues + 1
elseif type(current[k]) == 'table' and type(v) == 'table' then
current, _changedValues = fillEmptyKeys(v, current[k])
changedValues = changedValues + _changedValues
end
end
return current, changedValues
end
local function save(data)
local encodeStatus, JSON = pcall(encodeJson, data)
if not encodeStatus or JSON == nil then
return false, 'encode error'
end
local fileHandle = io.open(file, 'w')
if not fileHandle then return false, 'cannot open file' end
fileHandle:write(JSON)
fileHandle:close()
end
local function load()
if not doesFileExist(file) then
save(default)
end
local fileHandle = io.open(file, 'r')
if not fileHandle then return false, {}, 'cannot open file' end
local content = fileHandle:read('*a')
fileHandle:close()
local decodeStatus, data = pcall(decodeJson, content)
if not decodeStatus or data == nil then return false, {}, 'decode error' end
local data, changedValues = fillEmptyKeys(default, data)
if changedValues > 0 then save(data) end
return decodeStatus, data, 'ok'
end
local loadStatus, data, msg = load()
return loadStatus, loadStatus and setmetatable(data, {
__call = function(self)
save(self)
end
}) or {}, msg
end