local parse_inline_options = require "luacheck.stages.parse_inline_options"
local stages = require "luacheck.stages"
local utils = require "luacheck.utils"
local serializer = {}
local option_fields = {
"ignore", "std", "globals", "unused_args", "self", "compat", "global", "unused", "redefined",
"unused_secondaries", "allow_defined", "allow_defined_top", "module",
"read_globals", "new_globals", "new_read_globals", "enable", "only", "not_globals",
"max_line_length", "max_code_line_length", "max_string_line_length", "max_comment_line_length",
"max_cyclomatic_complexity", "operators"
}
local function compress_table(t, fields)
local res = {}
for index, field in ipairs(fields) do
local value = t[field]
if value ~= nil then
if field == "options" then
value = compress_table(value, option_fields)
end
res[index] = value
end
end
return res
end
local function compress_tables(tables, per_code_fields)
local res = {}
for _, t in ipairs(tables) do
local fields = per_code_fields and stages.warnings[t.code].fields or parse_inline_options.inline_option_fields
table.insert(res, compress_table(t, fields))
end
return res
end
local function compress_result(result)
local res = {}
res[1] = compress_tables(result.warnings, true)
res[2] = compress_tables(result.inline_options)
res[3] = result.line_lengths
res[4] = result.line_endings
return res
end
local function decompress_table(t, fields)
local res = {}
for index, field in ipairs(fields) do
local value = t[index]
if value ~= nil then
if field == "options" then
value = decompress_table(value, option_fields)
end
res[field] = value
end
end
return res
end
local function decompress_tables(tables, per_code_fields)
local res = {}
for _, t in ipairs(tables) do
local fields
if per_code_fields then
fields = stages.warnings[t[1]].fields
else
fields = parse_inline_options.inline_option_fields
end
table.insert(res, decompress_table(t, fields))
end
return res
end
local function decompress_result(compressed)
local result = {}
result.warnings = decompress_tables(compressed[1], true)
result.inline_options = decompress_tables(compressed[2])
result.line_lengths = compressed[3]
result.line_endings = compressed[4]
return result
end
local function get_local_name(index)
return string.char(index + (index > 26 and 70 or 64))
end
local function max_n(t)
local res = 0
for k in pairs(t) do
res = math.max(res, k)
end
return res
end
local function add_value(buffer, strings, value, level)
if type(value) == "string" then
local prev = strings[value]
if type(prev) == "string" then
table.insert(buffer, prev)
elseif type(prev) == "number" and #strings < 52 then
table.insert(strings, ("%q"):format(value))
local local_name = get_local_name(#strings)
buffer[prev] = local_name
table.insert(buffer, local_name)
strings[value] = local_name
else
table.insert(buffer, ("%q"):format(value))
strings[value] = #buffer
end
elseif type(value) == "table" then
local allow_sparse = level ~= 3
local nil_tail_start
local is_sparse
local put_one
table.insert(buffer, "{")
for index = 1, max_n(value) do
local item = value[index]
if item == nil then
is_sparse = allow_sparse
nil_tail_start = nil_tail_start or index
else
if put_one then
table.insert(buffer, ",")
end
if is_sparse then
table.insert(buffer, ("[%d]="):format(index))
elseif nil_tail_start then
for _ = nil_tail_start, index - 1 do
table.insert(buffer, "nil,")
end
nil_tail_start = nil
end
add_value(buffer, strings, item, level + 1)
put_one = true
end
end
table.insert(buffer, "}")
else
table.insert(buffer, tostring(value))
end
end
function serializer.dump_check_result(result)
local strings = {}
local buffer = {"", "return "}
add_value(buffer, strings, compress_result(result), 1)
if strings[1] then
local names = {}
for index in ipairs(strings) do
table.insert(names, get_local_name(index))
end
buffer[1] = "local " .. table.concat(names, ",") .. "=" .. table.concat(strings, ",") .. ";"
end
return table.concat(buffer)
end
function serializer.load_check_result(dumped)
local func = utils.load(dumped, {})
if not func then
return
end
local ok, compressed_result = pcall(func)
if not ok or type(compressed_result) ~= "table" then
return
end
return decompress_result(compressed_result)
end
return serializer