176 lines
4.6 KiB
Lua
176 lines
4.6 KiB
Lua
local json = require "json"
|
|
local type = type
|
|
local next = next
|
|
local error = error
|
|
local table_concat = table.concat
|
|
local table_sort = table.sort
|
|
local string_rep = string.rep
|
|
local setmetatable = setmetatable
|
|
|
|
local math_type
|
|
|
|
if _VERSION == "Lua 5.1" or _VERSION == "Lua 5.2" then
|
|
local math_floor = math.floor
|
|
function math_type(v)
|
|
if v >= -2147483648 and v <= 2147483647 and math_floor(v) == v then
|
|
return "integer"
|
|
end
|
|
return "float"
|
|
end
|
|
else
|
|
math_type = math.type
|
|
end
|
|
|
|
local statusVisited
|
|
local statusBuilder
|
|
local statusDep
|
|
local statusOpt
|
|
|
|
local defaultOpt = {
|
|
newline = "\n",
|
|
indent = " ",
|
|
depth = 0,
|
|
}
|
|
defaultOpt.__index = defaultOpt
|
|
|
|
local function encode_newline()
|
|
statusBuilder[#statusBuilder+1] = statusOpt.newline..string_rep(statusOpt.indent, statusDep)
|
|
end
|
|
|
|
local encode_map = {}
|
|
local encode_string = json._encode_string
|
|
for k ,v in next, json._encode_map do
|
|
encode_map[k] = v
|
|
end
|
|
|
|
local function encode(v)
|
|
local res = encode_map[type(v)](v)
|
|
statusBuilder[#statusBuilder+1] = res
|
|
end
|
|
|
|
function encode_map.string(v)
|
|
statusBuilder[#statusBuilder+1] = '"'
|
|
statusBuilder[#statusBuilder+1] = encode_string(v)
|
|
return '"'
|
|
end
|
|
|
|
function encode_map.table(t)
|
|
local first_val = next(t)
|
|
if first_val == nil then
|
|
if json.isObject(t) then
|
|
return "{}"
|
|
else
|
|
return "[]"
|
|
end
|
|
end
|
|
if statusVisited[t] then
|
|
error("circular reference")
|
|
end
|
|
statusVisited[t] = true
|
|
if type(first_val) == 'string' then
|
|
local key = {}
|
|
for k in next, t do
|
|
if type(k) ~= "string" then
|
|
error("invalid table: mixed or invalid key types: "..k)
|
|
end
|
|
key[#key+1] = k
|
|
end
|
|
table_sort(key)
|
|
statusBuilder[#statusBuilder+1] = "{"
|
|
statusDep = statusDep + 1
|
|
encode_newline()
|
|
do
|
|
local k = key[1]
|
|
statusBuilder[#statusBuilder+1] = '"'
|
|
statusBuilder[#statusBuilder+1] = encode_string(k)
|
|
statusBuilder[#statusBuilder+1] = '": '
|
|
encode(t[k])
|
|
end
|
|
for i = 2, #key do
|
|
local k = key[i]
|
|
statusBuilder[#statusBuilder+1] = ","
|
|
encode_newline()
|
|
statusBuilder[#statusBuilder+1] = '"'
|
|
statusBuilder[#statusBuilder+1] = encode_string(k)
|
|
statusBuilder[#statusBuilder+1] = '": '
|
|
encode(t[k])
|
|
end
|
|
statusDep = statusDep - 1
|
|
encode_newline()
|
|
statusVisited[t] = nil
|
|
return "}"
|
|
elseif json.supportSparseArray then
|
|
local max = 0
|
|
for k in next, t do
|
|
if math_type(k) ~= "integer" or k <= 0 then
|
|
error("invalid table: mixed or invalid key types: "..k)
|
|
end
|
|
if max < k then
|
|
max = k
|
|
end
|
|
end
|
|
statusBuilder[#statusBuilder+1] = "["
|
|
statusDep = statusDep + 1
|
|
encode_newline()
|
|
encode(t[1])
|
|
for i = 2, max do
|
|
statusBuilder[#statusBuilder+1] = ","
|
|
encode_newline()
|
|
encode(t[i])
|
|
end
|
|
statusDep = statusDep - 1
|
|
encode_newline()
|
|
statusVisited[t] = nil
|
|
return "]"
|
|
else
|
|
if t[1] == nil then
|
|
error("invalid table: sparse array is not supported")
|
|
end
|
|
statusBuilder[#statusBuilder+1] = "["
|
|
statusDep = statusDep + 1
|
|
encode_newline()
|
|
encode(t[1])
|
|
local count = 2
|
|
while t[count] ~= nil do
|
|
statusBuilder[#statusBuilder+1] = ","
|
|
encode_newline()
|
|
encode(t[count])
|
|
count = count + 1
|
|
end
|
|
if next(t, count-1) ~= nil then
|
|
local k = next(t, count-1)
|
|
if type(k) == "number" then
|
|
error("invalid table: sparse array is not supported")
|
|
else
|
|
error("invalid table: mixed or invalid key types: "..k)
|
|
end
|
|
end
|
|
statusDep = statusDep - 1
|
|
encode_newline()
|
|
statusVisited[t] = nil
|
|
return "]"
|
|
end
|
|
end
|
|
|
|
local function beautify_option(option)
|
|
return setmetatable(option or {}, defaultOpt)
|
|
end
|
|
|
|
local function beautify_builder(builder, v, option)
|
|
statusVisited = {}
|
|
statusBuilder = builder
|
|
statusOpt = beautify_option(option)
|
|
statusDep = statusOpt.depth
|
|
encode(v)
|
|
end
|
|
|
|
local function beautify(v, option)
|
|
beautify_builder({}, v, option)
|
|
return table_concat(statusBuilder)
|
|
end
|
|
|
|
json.beautify = beautify
|
|
json._beautify_builder = beautify_builder
|
|
json._beautify_option = beautify_option
|
|
|
|
return json
|