|
| 1 | +# [cjson](https://github.com/mpx/lua-cjson) |
| 2 | + |
| 3 | +Lua JSON encoding/decoding module. |
| 4 | + |
| 5 | +The cjson module is embedded directly into Millennium. Although Millennium's fork of cjson is slightly different under the hood, everything will still work the same. Although these docs should cover everything you need, you can refer to their documentation [here](https://kyne.au/%7Emark/software/lua-cjson-manual.html). |
| 6 | + |
| 7 | +The cjson module can be imported directly into any lua file in your backend. |
| 8 | + |
| 9 | +```lua |
| 10 | +local cjson = require("cjson") |
| 11 | +``` |
| 12 | + |
| 13 | +## Functions |
| 14 | + |
| 15 | +- `cjson.encode(value)` - Encode Lua value to JSON string |
| 16 | +- `cjson.decode(json_string)` - Decode JSON string to Lua value |
| 17 | +- `cjson.new()` - Create new CJSON instance |
| 18 | +- `cjson.encode_sparse_array([convert, ratio, safe])` - Configure sparse array encoding |
| 19 | +- `cjson.encode_max_depth([depth])` - Configure maximum encoding depth |
| 20 | +- `cjson.decode_max_depth([depth])` - Configure maximum decoding depth |
| 21 | +- `cjson.encode_number_precision([precision])` - Configure number precision |
| 22 | +- `cjson.encode_keep_buffer([keep])` - Configure buffer persistence |
| 23 | +- `cjson.encode_invalid_numbers([setting])` - Configure invalid number encoding |
| 24 | +- `cjson.decode_invalid_numbers([setting])` - Configure invalid number decoding |
| 25 | +- `cjson.safe.encode(value)` - Safe encode (returns nil, error on failure) |
| 26 | +- `cjson.safe.decode(json_string)` - Safe decode (returns nil, error on failure) |
| 27 | +- `cjson.safe.new()` - Create new safe CJSON instance |
| 28 | + |
| 29 | +## Module Fields |
| 30 | + |
| 31 | +- `cjson.null` - Lightuserdata representing JSON null values |
| 32 | +- `cjson._NAME` - Module name string |
| 33 | +- `cjson._VERSION` - Module version string |
| 34 | + |
| 35 | +## Core Functions |
| 36 | + |
| 37 | +### cjson.encode(value) |
| 38 | + |
| 39 | +Encodes a Lua value as a JSON string. |
| 40 | + |
| 41 | +**Parameters:** |
| 42 | + |
| 43 | +- `value` (any) - The Lua value to encode |
| 44 | + |
| 45 | +**Returns:** JSON string representation |
| 46 | + |
| 47 | +**Throws:** Error on encoding failure |
| 48 | + |
| 49 | +**Usage:** |
| 50 | + |
| 51 | +```lua |
| 52 | +local json_str = cjson.encode({ name = "John", age = 30, active = true }) |
| 53 | +-- Result: '{"name":"John","age":30,"active":true}' |
| 54 | + |
| 55 | +local array_json = cjson.encode({ 1, 2, 3, 4, 5 }) |
| 56 | +-- Result: '[1,2,3,4,5]' |
| 57 | +``` |
| 58 | + |
| 59 | +--- |
| 60 | + |
| 61 | +### cjson.decode(json_string) |
| 62 | + |
| 63 | +Decodes a JSON string into a Lua value. |
| 64 | + |
| 65 | +**Parameters:** |
| 66 | + |
| 67 | +- `json_string` (string) - The JSON string to decode |
| 68 | + |
| 69 | +**Returns:** The decoded Lua value |
| 70 | + |
| 71 | +**Throws:** Error on decoding failure |
| 72 | + |
| 73 | +**Usage:** |
| 74 | + |
| 75 | +```lua |
| 76 | +local data = cjson.decode('{"name":"John","age":30}') |
| 77 | +print(data.name) -- "John" |
| 78 | +print(data.age) -- 30 |
| 79 | + |
| 80 | +local array = cjson.decode('[1,2,3,4,5]') |
| 81 | +print(array[1]) -- 1 |
| 82 | +``` |
| 83 | + |
| 84 | +--- |
| 85 | + |
| 86 | +### cjson.new() |
| 87 | + |
| 88 | +Creates a new CJSON instance with default configuration. |
| 89 | + |
| 90 | +**Returns:** New cjson instance |
| 91 | + |
| 92 | +**Usage:** |
| 93 | + |
| 94 | +```lua |
| 95 | +local custom_json = cjson.new() |
| 96 | +custom_json.encode_max_depth(5) |
| 97 | +custom_json.encode_number_precision(3) |
| 98 | + |
| 99 | +local json_str = custom_json.encode({ value = 3.14159 }) |
| 100 | +-- Custom instance has its own configuration |
| 101 | +``` |
| 102 | + |
| 103 | +--- |
| 104 | + |
| 105 | +## Configuration Functions |
| 106 | + |
| 107 | +### cjson.encode_sparse_array([convert, ratio, safe]) |
| 108 | + |
| 109 | +Configures sparse array encoding. Arrays exceeding the sparseness threshold are encoded as objects. |
| 110 | + |
| 111 | +**Parameters:** |
| 112 | + |
| 113 | +- `convert` (boolean|integer, optional) - Convert sparse arrays to objects (default: false) |
| 114 | +- `ratio` (integer, optional) - Sparseness ratio threshold (default: 2) |
| 115 | +- `safe` (integer, optional) - Always use array when max index ≤ safe (default: 10) |
| 116 | + |
| 117 | +**Returns:** Current settings (convert, ratio, safe) |
| 118 | + |
| 119 | +**Usage:** |
| 120 | + |
| 121 | +```lua |
| 122 | +-- Get current settings |
| 123 | +local convert, ratio, safe = cjson.encode_sparse_array() |
| 124 | + |
| 125 | +-- Enable sparse array conversion with ratio 3, safe 5 |
| 126 | +cjson.encode_sparse_array(true, 3, 5) |
| 127 | + |
| 128 | +local sparse = { [1] = "a", [100] = "b" } |
| 129 | +local json = cjson.encode(sparse) |
| 130 | +-- Encoded as object: '{"1":"a","100":"b"}' |
| 131 | +``` |
| 132 | + |
| 133 | +--- |
| 134 | + |
| 135 | +### cjson.encode_max_depth([depth]) |
| 136 | + |
| 137 | +Configures maximum encoding nesting depth. |
| 138 | + |
| 139 | +**Parameters:** |
| 140 | + |
| 141 | +- `depth` (integer, optional) - Maximum depth, range 1-2147483647 (default: 1000) |
| 142 | + |
| 143 | +**Returns:** Current maximum depth |
| 144 | + |
| 145 | +**Usage:** |
| 146 | + |
| 147 | +```lua |
| 148 | +-- Get current depth |
| 149 | +local current = cjson.encode_max_depth() |
| 150 | + |
| 151 | +-- Set max depth to 5 |
| 152 | +cjson.encode_max_depth(5) |
| 153 | + |
| 154 | +-- This will fail if nesting exceeds 5 levels |
| 155 | +local deeply_nested = { { { { { { "too deep" } } } } } } |
| 156 | +-- cjson.encode(deeply_nested) -- Error: exceeds max depth |
| 157 | +``` |
| 158 | + |
| 159 | +--- |
| 160 | + |
| 161 | +### cjson.decode_max_depth([depth]) |
| 162 | + |
| 163 | +Configures maximum decoding nesting depth. |
| 164 | + |
| 165 | +**Parameters:** |
| 166 | + |
| 167 | +- `depth` (integer, optional) - Maximum depth, range 1-2147483647 (default: 1000) |
| 168 | + |
| 169 | +**Returns:** Current maximum depth |
| 170 | + |
| 171 | +**Usage:** |
| 172 | + |
| 173 | +```lua |
| 174 | +-- Set max decoding depth to 10 |
| 175 | +cjson.decode_max_depth(10) |
| 176 | + |
| 177 | +-- This will fail if JSON nesting exceeds 10 levels |
| 178 | +local json = '{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":{"i":{"j":{"k":"value"}}}}}}}}}}}' |
| 179 | +-- cjson.decode(json) -- Error: exceeds max depth |
| 180 | +``` |
| 181 | + |
| 182 | +--- |
| 183 | + |
| 184 | +### cjson.encode_number_precision([precision]) |
| 185 | + |
| 186 | +Configures decimal precision for number encoding. |
| 187 | + |
| 188 | +**Parameters:** |
| 189 | + |
| 190 | +- `precision` (integer, optional) - Precision, range 1-14 (default: 14) |
| 191 | + |
| 192 | +**Returns:** Current precision setting |
| 193 | + |
| 194 | +**Usage:** |
| 195 | + |
| 196 | +```lua |
| 197 | +-- Set precision to 2 decimal places |
| 198 | +cjson.encode_number_precision(2) |
| 199 | + |
| 200 | +local json = cjson.encode({ pi = 3.14159265359 }) |
| 201 | +-- Result: '{"pi":3.14}' |
| 202 | + |
| 203 | +-- Reset to full precision |
| 204 | +cjson.encode_number_precision(14) |
| 205 | +``` |
| 206 | + |
| 207 | +--- |
| 208 | + |
| 209 | +### cjson.encode_keep_buffer([keep]) |
| 210 | + |
| 211 | +Configures whether the encoding buffer persists between calls. |
| 212 | + |
| 213 | +**Parameters:** |
| 214 | + |
| 215 | +- `keep` (boolean, optional) - Keep buffer between calls (default: true) |
| 216 | + |
| 217 | +**Returns:** Current buffer setting |
| 218 | + |
| 219 | +**Usage:** |
| 220 | + |
| 221 | +```lua |
| 222 | +-- Disable buffer persistence (may reduce memory usage) |
| 223 | +cjson.encode_keep_buffer(false) |
| 224 | + |
| 225 | +-- Re-enable buffer persistence (better performance) |
| 226 | +cjson.encode_keep_buffer(true) |
| 227 | + |
| 228 | +local json = cjson.encode({ data = "value" }) |
| 229 | +``` |
| 230 | + |
| 231 | +--- |
| 232 | + |
| 233 | +### cjson.encode_invalid_numbers([setting]) |
| 234 | + |
| 235 | +Configures how invalid numbers (NaN, Inf) are encoded. |
| 236 | + |
| 237 | +**Parameters:** |
| 238 | + |
| 239 | +- `setting` (boolean|string, optional) - "off", "on", "null", or boolean (default: "off") |
| 240 | + |
| 241 | +**Returns:** Current setting |
| 242 | + |
| 243 | +**Usage:** |
| 244 | + |
| 245 | +```lua |
| 246 | +-- Encode invalid numbers as null |
| 247 | +cjson.encode_invalid_numbers("null") |
| 248 | + |
| 249 | +local json = cjson.encode({ value = 0/0 }) -- NaN |
| 250 | +-- Result: '{"value":null}' |
| 251 | + |
| 252 | +-- Allow invalid numbers (non-standard JSON) |
| 253 | +cjson.encode_invalid_numbers(true) |
| 254 | + |
| 255 | +local json = cjson.encode({ inf = math.huge }) |
| 256 | +-- Result: '{"inf":inf}' |
| 257 | +``` |
| 258 | + |
| 259 | +--- |
| 260 | + |
| 261 | +### cjson.decode_invalid_numbers([setting]) |
| 262 | + |
| 263 | +Configures whether invalid numbers are allowed during decoding. |
| 264 | + |
| 265 | +**Parameters:** |
| 266 | + |
| 267 | +- `setting` (boolean, optional) - Allow invalid numbers (default: true) |
| 268 | + |
| 269 | +**Returns:** Current setting |
| 270 | + |
| 271 | +**Usage:** |
| 272 | + |
| 273 | +```lua |
| 274 | +-- Allow decoding of invalid numbers (default) |
| 275 | +cjson.decode_invalid_numbers(true) |
| 276 | + |
| 277 | +local data = cjson.decode('{"value":NaN,"inf":Infinity}') |
| 278 | +-- Accepts non-standard JSON with NaN/Infinity |
| 279 | + |
| 280 | +-- Strict mode: reject invalid numbers |
| 281 | +cjson.decode_invalid_numbers(false) |
| 282 | +-- cjson.decode('{"value":NaN}') -- Error |
| 283 | +``` |
| 284 | + |
| 285 | +--- |
| 286 | + |
| 287 | +## Safe Variant |
| 288 | + |
| 289 | +`cjson.safe` provides error-safe versions of encode/decode that return `nil, error_message` instead of throwing. |
| 290 | + |
| 291 | +### cjson.safe.encode(value) |
| 292 | + |
| 293 | +**Returns:** JSON string on success, or `nil, error_message` on failure |
| 294 | + |
| 295 | +**Usage:** |
| 296 | + |
| 297 | +```lua |
| 298 | +local json, err = cjson.safe.encode({ name = "John" }) |
| 299 | +if not json then |
| 300 | + print("Encoding failed: " .. err) |
| 301 | +else |
| 302 | + print("Success: " .. json) |
| 303 | +end |
| 304 | + |
| 305 | +-- Handle encoding errors gracefully |
| 306 | +local json, err = cjson.safe.encode({ func = function() end }) |
| 307 | +if not json then |
| 308 | + print("Cannot encode functions: " .. err) |
| 309 | +end |
| 310 | +``` |
| 311 | + |
| 312 | +--- |
| 313 | + |
| 314 | +### cjson.safe.decode(json_string) |
| 315 | + |
| 316 | +**Returns:** Decoded value on success, or `nil, error_message` on failure |
| 317 | + |
| 318 | +**Usage:** |
| 319 | + |
| 320 | +```lua |
| 321 | +local data, err = cjson.safe.decode('{"name":"John"}') |
| 322 | +if not data then |
| 323 | + print("Decoding failed: " .. err) |
| 324 | +else |
| 325 | + print("Name: " .. data.name) |
| 326 | +end |
| 327 | + |
| 328 | +-- Handle malformed JSON |
| 329 | +local data, err = cjson.safe.decode('invalid json') |
| 330 | +if not data then |
| 331 | + print("Parse error: " .. err) |
| 332 | +end |
| 333 | +``` |
| 334 | + |
| 335 | +--- |
| 336 | + |
| 337 | +### cjson.safe.new() |
| 338 | + |
| 339 | +**Returns:** New safe CJSON instance |
| 340 | + |
| 341 | +**Usage:** |
| 342 | + |
| 343 | +```lua |
| 344 | +local safe_json = cjson.safe.new() |
| 345 | +safe_json.encode_max_depth(5) |
| 346 | + |
| 347 | +local json, err = safe_json.encode({ data = "value" }) |
| 348 | +if not json then |
| 349 | + print("Error: " .. err) |
| 350 | +end |
| 351 | +``` |
| 352 | + |
| 353 | +--- |
| 354 | + |
| 355 | +All configuration functions and module fields are identical to the regular `cjson` module. |
0 commit comments