1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
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
|