mirror of
https://github.com/Myzel394/jsonfly.nvim.git
synced 2025-06-18 04:05:26 +02:00
188 lines
4.7 KiB
Lua
188 lines
4.7 KiB
Lua
---@class EntryPosition
|
|
---@field line_number number
|
|
---@field key_start number
|
|
---@field value_start number
|
|
--
|
|
---@class Entry
|
|
---@field key string
|
|
---@field value Entry|table|number|string|boolean|nil
|
|
---@field position EntryPosition
|
|
--
|
|
---@class JSONEntry
|
|
---@field value JSONEntry|string|number|boolean|nil
|
|
---@field line_number number
|
|
---@field value_start number
|
|
---@field key_start number
|
|
|
|
local PRIMITIVE_TYPES = {
|
|
string = true,
|
|
number = true,
|
|
boolean = true,
|
|
}
|
|
|
|
local M = {}
|
|
|
|
---@param entry JSONEntry
|
|
local function get_contents_from_json_value(entry)
|
|
local value = entry.value
|
|
|
|
if type(value) == "table" then
|
|
-- Recursively get the contents of the table
|
|
local contents = {}
|
|
|
|
for k, v in pairs(value) do
|
|
contents[k] = get_contents_from_json_value(v)
|
|
end
|
|
|
|
return contents
|
|
else
|
|
return entry.value
|
|
end
|
|
end
|
|
|
|
---@param t table|nil|string|number
|
|
---@return Entry[]
|
|
function M:get_entries_from_lua_json(t)
|
|
if PRIMITIVE_TYPES[type(t)] or t == nil then
|
|
return {}
|
|
end
|
|
|
|
local keys = {}
|
|
|
|
for k, _raw_value in pairs(t) do
|
|
---@type JSONEntry
|
|
local raw_value = _raw_value
|
|
---@type Entry
|
|
local entry = {
|
|
key = k,
|
|
value = get_contents_from_json_value(raw_value),
|
|
position = {
|
|
line_number = raw_value.line_number,
|
|
key_start = raw_value.key_start,
|
|
value_start = raw_value.value_start,
|
|
}
|
|
}
|
|
table.insert(keys, entry)
|
|
|
|
local v = raw_value.value
|
|
|
|
if type(v) == "table" then
|
|
local sub_keys = M:get_entries_from_lua_json(v)
|
|
|
|
for index=1, #sub_keys do
|
|
local sub_key = sub_keys[index]
|
|
|
|
---@type Entry
|
|
local entry = {
|
|
key = k .. "." .. sub_key.key,
|
|
value = sub_key.value,
|
|
position = sub_key.position,
|
|
}
|
|
|
|
keys[#keys + 1] = entry
|
|
end
|
|
end
|
|
end
|
|
|
|
return keys
|
|
end
|
|
|
|
---@param result Symbol
|
|
---@return string|number|table|boolean|nil
|
|
function M:parse_lsp_value(result)
|
|
-- Object
|
|
if result.kind == 2 then
|
|
local value = {}
|
|
|
|
for _, child in ipairs(result.children) do
|
|
value[child.name] = M:parse_lsp_value(child)
|
|
end
|
|
|
|
return value
|
|
-- Integer
|
|
elseif result.kind == 16 then
|
|
return tonumber(result.detail)
|
|
-- String
|
|
elseif result.kind == 15 then
|
|
return result.detail
|
|
-- Array
|
|
elseif result.kind == 18 then
|
|
local value = {}
|
|
|
|
for i, child in ipairs(result.children) do
|
|
value[i] = M:parse_lsp_value(child)
|
|
end
|
|
|
|
return value
|
|
-- null
|
|
elseif result.kind == 13 then
|
|
return nil
|
|
-- boolean
|
|
elseif result.kind == 17 then
|
|
return result.detail == "true"
|
|
end
|
|
end
|
|
|
|
|
|
---@class Symbol
|
|
---@field name string
|
|
---@field kind number 2 = Object, 16 = Number, 15 = String, 18 = Array, 13 = Null, 17 = Boolean
|
|
---@field range Range
|
|
---@field selectionRange Range
|
|
---@field detail string
|
|
---@field children Symbol[]
|
|
--
|
|
---@class Range
|
|
---@field start Position
|
|
---@field ["end"] Position
|
|
--
|
|
---@class Position
|
|
---@field line number
|
|
---@field character number
|
|
--
|
|
---@param symbols Symbol[]
|
|
---@return Entry[]
|
|
function M:get_entries_from_lsp_symbols(symbols)
|
|
local keys = {}
|
|
|
|
for index=1, #symbols do
|
|
local symbol = symbols[index]
|
|
local key = symbol.name
|
|
|
|
---@type Entry
|
|
local entry = {
|
|
key = key,
|
|
value = M:parse_lsp_value(symbol),
|
|
position = {
|
|
line_number = symbol.range.start.line + 1,
|
|
key_start = symbol.range.start.character + 2,
|
|
-- The LSP doesn't return the start of the value, so we'll just assume it's 3 characters after the key
|
|
-- We assume a default JSON file like:
|
|
-- `"my_key": "my_value"`
|
|
-- Since we get the end of the key, we can just add 4 to get the start of the value
|
|
value_start = symbol.selectionRange["end"].character + 3,
|
|
}
|
|
}
|
|
keys[#keys + 1] = entry
|
|
|
|
if symbol.kind == 2 or symbol.kind == 18 then
|
|
local sub_keys = M:get_entries_from_lsp_symbols(symbol.children)
|
|
|
|
for jindex=1, #sub_keys do
|
|
---@type Entry
|
|
local entry = {
|
|
key = key .. "." .. sub_keys[jindex].key,
|
|
value = sub_keys[jindex].value,
|
|
position = sub_keys[jindex].position,
|
|
}
|
|
|
|
keys[#keys + 1] = entry
|
|
end
|
|
end
|
|
end
|
|
|
|
return keys
|
|
end
|
|
|
|
return M
|