feat(plugins): add JSON parsing/serialization (#6420)

Reviewed-by: Mm2PL <mm2pl+gh@kotmisia.pl>
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
nerix
2025-11-21 17:43:28 +01:00
committed by GitHub
parent 115428d7f4
commit b63739e792
17 changed files with 1509 additions and 4 deletions
+137
View File
@@ -0,0 +1,137 @@
local json = require('chatterino.json')
local function check_err(...)
local ok = pcall(json.stringify, ...)
assert(not ok, "expected an error")
end
---@param input any
---@param expected string|string[]
---@vararg { pretty: boolean, indent_char: string, indent_size: number }|any
local function check_ok(input, expected, ...)
local got = json.stringify(input, ...)
if type(expected) == "string" then
assert(got == expected, "Failed:\n\texpected: " .. expected .. "\n\tgot: " .. got .. "\n")
else
local ok = false
for _, it in ipairs(expected) do
if it == got then
ok = true
break
end
end
assert(ok, "Output did not match any of the expected values")
end
end
assert(type(json.null) == "userdata")
-- empty
check_ok({}, "{}")
check_ok({ [0] = json.null }, '[]')
-- scalars
check_ok(1, "1")
check_ok("foo", '"foo"')
check_ok("foo\n", '"foo\\n"')
check_ok(true, "true")
check_ok(false, "false")
check_ok(nil, "null")
check_ok(json.null, "null")
check_ok(1.23, "1.23")
-- arrays
check_ok({ 1, 2 }, "[1,2]")
check_ok({ 1, 2, nil }, "[1,2]")
check_ok({ 1, 2, json.null }, "[1,2,null]")
check_ok({ 1, nil, 2 }, "[1,null,2]")
check_ok({ 1, [10] = 2 }, "[1,null,null,null,null,null,null,null,null,2]")
check_ok({ [10 / 2] = 1 }, '[null,null,null,null,1]')
check_ok({ { { { { 1 } } } } }, "[[[[[1]]]]]")
check_ok({ { { { { 1 } } }, { foo = 1 } } }, '[[[[[1]]],{"foo":1}]]')
-- objects
check_ok({ ok = { baz = "str", [""] = { 1, 2 } } }, {
'{"ok":{"baz":"str","":[1,2]}}',
'{"ok":{"":[1,2],"baz":"str"}}',
})
check_ok({ ok = { 1, 2 } }, '{"ok":[1,2]}')
check_ok({ ['\n\tlol'] = { 1, 2 } }, '{"\\n\\tlol":[1,2]}')
check_ok({ foo = nil }, '{}')
check_ok({ foo = json.null }, '{"foo":null}')
local meta_haver = {}
local my_meta = {
foo = 42,
__index = function()
return 1
end
}
setmetatable(meta_haver, my_meta)
assert(meta_haver.xd == 1)
check_ok(meta_haver, '{}')
meta_haver.xd = 2 -- uses __newindex
check_ok(meta_haver, '{"xd":2}')
-- limits
local big_obj = {}
; (function()
local it = big_obj
for _ = 1, 255 do
it.x = {}
it = it.x
end
it.x = "hey"
end)()
check_ok(big_obj, string.rep('{"x":', 256) .. '"hey"' .. string.rep('}', 256))
check_err({ x = big_obj })
local big_arr = {}
; (function()
local it = big_arr
for _ = 1, 255 do
it[1] = {}
it = it[1]
end
it[1] = 1
end)()
check_ok(big_arr, string.rep('[', 256) .. '1' .. string.rep(']', 256))
check_err({ big_arr })
-- errors
check_err(c2.Message.new({}))
check_err(coroutine.create(function() end))
check_err({ 1, 2, bar = "lol" })
check_err({ [-1] = 3 })
check_err({ [0] = 3 })
check_err({ [0] = "42" })
check_err({ [-1] = json.null })
check_err({ [1.1] = 3 })
check_err()
local recurse = {}
recurse.recurse = recurse
check_err(recurse) -- hits the depth limit
check_err(math.huge)
check_err(-math.huge)
check_err(0/0)
check_err(-(0/0))
-- ✨ pretty ✨
check_ok(1, "1", { pretty = true })
check_ok(false, "false", { pretty = true })
check_ok(nil, "null", { pretty = true })
check_ok("xd", '"xd"', { pretty = true })
check_ok({ 1 }, '[\n 1\n]', { pretty = true })
check_ok({ foo = "bar" }, '{\n "foo": "bar"\n}', { pretty = true })
check_ok({ foo = "bar", baz = 1 }, { [[{
"foo": "bar",
"baz": 1
}]], [[{
"baz": 1,
"foo": "bar"
}]] }, { pretty = true })
check_ok({ foo = "bar" }, '{\n "foo": "bar"\n}', { pretty = true, indent_size = 1 })
check_ok({ foo = "bar" }, '{\n\t"foo": "bar"\n}', { pretty = true, indent_size = 1, indent_char = '\t' })
check_ok({ foo = "bar" }, '{"foo":"bar"}', { indent_size = 1, indent_char = '\tlol' })