Finished(?) annotation parsing
Small fixes for the parser
This commit is contained in:
7
.github/workflows/main.yml
vendored
7
.github/workflows/main.yml
vendored
@@ -29,8 +29,11 @@ jobs:
|
||||
run: |
|
||||
lua tools/generate-config.lua
|
||||
|
||||
# Step 2: Generate LuaLS Definitions
|
||||
- name: Generate LuaLS
|
||||
run: |
|
||||
lua tools/generate-annotations.lua src
|
||||
|
||||
|
||||
# Step 3: Bundle and Minify
|
||||
- name: Bundle and Minify
|
||||
run: |
|
||||
@@ -74,6 +77,6 @@ jobs:
|
||||
run: |
|
||||
git config --global user.name 'github-actions[bot]'
|
||||
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
||||
git add config.lua src/LuaLS.lua release/basalt.lua CHANGELOG.md
|
||||
git add config.lua LuaLS.lua release/basalt.lua CHANGELOG.md
|
||||
git commit -m "Update config, LuaLS definitions, bundle and changelog" || exit 0
|
||||
git push
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,4 +6,3 @@ ascii.lua
|
||||
tests
|
||||
testWorkflows
|
||||
.vscode
|
||||
generate-annotations.lua
|
||||
2599
src/LuaLS.lua
2599
src/LuaLS.lua
File diff suppressed because it is too large
Load Diff
@@ -51,19 +51,22 @@ function Display:init(props, basalt)
|
||||
end
|
||||
|
||||
self:observe("width", function(self, width)
|
||||
local window = self.get("window")
|
||||
local window = self._window
|
||||
if window then
|
||||
window.reposition(1, 1, width, self.get("height"))
|
||||
end
|
||||
end)
|
||||
self:observe("height", function(self, height)
|
||||
local window = self.get("window")
|
||||
local window = self._window
|
||||
if window then
|
||||
window.reposition(1, 1, self.get("width"), height)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- Returns the current window object
|
||||
--- @shortDescription Returns the current window object
|
||||
--- @return table window The current window object
|
||||
function Display:getWindow()
|
||||
return self._window
|
||||
end
|
||||
|
||||
@@ -419,8 +419,7 @@ function VisualElement:setCursor(x, y, blink, color)
|
||||
return self
|
||||
end
|
||||
|
||||
--- This function is used to prioritize the element by moving it to the top of its parent's children.
|
||||
--- It removes the element from its parent and adds it back, effectively changing its order.
|
||||
--- This function is used to prioritize the element by moving it to the top of its parent's children. It removes the element from its parent and adds it back, effectively changing its order.
|
||||
--- @shortDescription Prioritizes the element by moving it to the top of its parent's children
|
||||
--- @return VisualElement self The VisualElement instance
|
||||
function VisualElement:prioritize()
|
||||
|
||||
@@ -163,6 +163,7 @@ function BaseElement:applyTheme()
|
||||
self.set(prop, value)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Gets the theme properties for this element
|
||||
@@ -179,26 +180,26 @@ end
|
||||
|
||||
--- The Theme API provides methods for managing themes globally
|
||||
---@class ThemeAPI
|
||||
local themeAPI = {}
|
||||
local ThemeAPI = {}
|
||||
|
||||
--- Sets the current theme
|
||||
--- @shortDescription Sets a new theme
|
||||
--- @param newTheme table The theme configuration to set
|
||||
function themeAPI.setTheme(newTheme)
|
||||
function ThemeAPI.setTheme(newTheme)
|
||||
themes.default = newTheme
|
||||
end
|
||||
|
||||
--- Gets the current theme configuration
|
||||
--- @shortDescription Gets the current theme
|
||||
--- @return table theme The current theme configuration
|
||||
function themeAPI.getTheme()
|
||||
function ThemeAPI.getTheme()
|
||||
return themes.default
|
||||
end
|
||||
|
||||
--- Loads a theme from a JSON file
|
||||
--- @shortDescription Loads theme from JSON file
|
||||
--- @param path string Path to the theme JSON file
|
||||
function themeAPI.loadTheme(path)
|
||||
function ThemeAPI.loadTheme(path)
|
||||
local file = fs.open(path, "r")
|
||||
if file then
|
||||
local content = file.readAll()
|
||||
@@ -209,5 +210,5 @@ end
|
||||
|
||||
return {
|
||||
BaseElement = BaseElement,
|
||||
API = themeAPI
|
||||
API = ThemeAPI
|
||||
}
|
||||
|
||||
@@ -375,7 +375,7 @@ function PropertySystem:observe(name, callback)
|
||||
end
|
||||
|
||||
--- Removes an observer from a property
|
||||
--- @NshortDescription Removes an observer from a property
|
||||
--- @shortDescription Removes an observer from a property
|
||||
--- @param name string The name of the property
|
||||
--- @param callback function The callback function to remove
|
||||
--- @return table self The PropertySystem
|
||||
|
||||
305
tools/generate-annotations.lua
Normal file
305
tools/generate-annotations.lua
Normal file
@@ -0,0 +1,305 @@
|
||||
local args = {...}
|
||||
|
||||
local commentTypes = {
|
||||
"module",
|
||||
"class",
|
||||
"param",
|
||||
"return",
|
||||
"usage",
|
||||
"function",
|
||||
"local",
|
||||
"property",
|
||||
"combinedProperty",
|
||||
"event",
|
||||
"private",
|
||||
"protected",
|
||||
"field",
|
||||
"vararg",
|
||||
"shortDescription",
|
||||
}
|
||||
|
||||
local elementList = {}
|
||||
|
||||
local function getFilesInCC(path)
|
||||
local files = {}
|
||||
|
||||
local function scanDir(dir)
|
||||
for _, item in ipairs(fs.list(dir)) do
|
||||
local fullPath = fs.combine(dir, item)
|
||||
if fs.isDir(fullPath) then
|
||||
scanDir(fullPath)
|
||||
elseif item:match("%.lua$") then
|
||||
if(fullPath:find("elements"))then
|
||||
local itemName = item:gsub("%.lua$", "")
|
||||
table.insert(elementList, itemName)
|
||||
end
|
||||
local file = fs.open(fullPath, "r")
|
||||
if file then
|
||||
files[fullPath] = file.readAll()
|
||||
file.close()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
scanDir(path)
|
||||
return files
|
||||
end
|
||||
|
||||
local function getFilesInLua(path)
|
||||
local files = {}
|
||||
|
||||
local function scanDir(dir)
|
||||
local p = io.popen('dir "'..dir..'" /b /s')
|
||||
if not p then return end
|
||||
|
||||
for file in p:lines() do
|
||||
if file:match("%.lua$") then
|
||||
if(file:find("elements"))then
|
||||
local itemName = file:gsub("%.lua$", "")
|
||||
itemName = itemName:match("([^/\\]+)$")
|
||||
table.insert(elementList, itemName)
|
||||
end
|
||||
local f = io.open(file, "r")
|
||||
if f then
|
||||
files[file] = f:read("*a")
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
p:close()
|
||||
end
|
||||
|
||||
scanDir(path)
|
||||
return files
|
||||
end
|
||||
|
||||
local function extractComment(line)
|
||||
local tripleContent = line:match("^%-%-%-%s*(.*)")
|
||||
if tripleContent then
|
||||
return tripleContent, true
|
||||
end
|
||||
|
||||
local doubleContent = line:match("^%-%- %s*(.*)")
|
||||
if doubleContent then
|
||||
return doubleContent, false
|
||||
end
|
||||
|
||||
return nil, false
|
||||
end
|
||||
|
||||
local function getCommentType(comment)
|
||||
for _, pattern in pairs(commentTypes) do
|
||||
if comment:match("^@"..pattern) then
|
||||
local content = comment:sub(#pattern + 2):gsub("^%s*", "")
|
||||
return pattern, content
|
||||
end
|
||||
end
|
||||
|
||||
return "desc", comment
|
||||
end
|
||||
|
||||
local function hasBlockContent(block)
|
||||
for key, _ in pairs(block) do
|
||||
if(key~="type")and(key~="desc")then
|
||||
return true
|
||||
end
|
||||
end
|
||||
if(#block.desc > 0)then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function getFunctionName(line)
|
||||
local pattern = "^function%s+([%w_%.:]-)%s*%("
|
||||
return line:match(pattern)
|
||||
end
|
||||
|
||||
local function split(str, delimiter)
|
||||
local result = {}
|
||||
for match in (str..delimiter):gmatch("(.-)"..delimiter) do
|
||||
table.insert(result, match)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function getClassName(content)
|
||||
return split(content:gsub("^%s*", ""):gsub("%s*$", ""):gsub(" ", ""), ":")
|
||||
end
|
||||
|
||||
local function parseFile(content)
|
||||
local fileContent = {}
|
||||
local class = {functions = {}, properties = {}, events = {}, fields = {}}
|
||||
local func = {params={}, returns={}, desc=""}
|
||||
local skipNextFunction = false
|
||||
|
||||
for line in content:gsub("\r\n", "\n"):gmatch("([^\n]*)\n?") do
|
||||
if line:match("^%s*$") or line == "" then
|
||||
-- Skip empty lines
|
||||
func = {params={}, returns={}, desc=""}
|
||||
else
|
||||
local comment, isDoc = extractComment(line)
|
||||
if comment then
|
||||
local commentType, content = getCommentType(comment)
|
||||
if(commentType=="module")then
|
||||
class.module = content
|
||||
elseif(commentType=="class")then
|
||||
if(class.class)then
|
||||
fileContent[class.class] = class
|
||||
class = {functions = {}, properties = {}, events = {}, fields = {}}
|
||||
end
|
||||
class.class, class.parent = table.unpack(getClassName(content))
|
||||
if(class.class=="Container")then
|
||||
for _,v in ipairs(elementList)do
|
||||
class.functions["Container:add"..v] = {params={{name="self", type="Container", desc="self"}, {name="props", type="table", desc="Optional: properties for the element.", optional=true}}, returns={{type=v, desc="element A new "..v.." element."}}, desc="Creates a new "..v.." element.\n"}
|
||||
end
|
||||
end
|
||||
elseif(commentType=="param")then
|
||||
if func then
|
||||
local paramName, paramType, paramDesc = content:match("^%s*([%w_]+)%s+([%w_]+)%s*(.*)$")
|
||||
if paramName then
|
||||
table.insert(func.params, {name=paramName, type=paramType, desc=paramDesc or ""})
|
||||
end
|
||||
end
|
||||
elseif(commentType=="return")then
|
||||
if func then
|
||||
local returnType, returnDesc = content:match("^%s*([%w_]+)%s*(.*)$")
|
||||
if returnType then
|
||||
table.insert(func.returns, {type=returnType, desc=returnDesc or ""})
|
||||
end
|
||||
end
|
||||
elseif(commentType=="usage")then
|
||||
if func then
|
||||
func.usage = content
|
||||
end
|
||||
elseif(commentType=="desc")then
|
||||
if func then
|
||||
func.desc = (func.desc or "") .. content .. "\n"
|
||||
end
|
||||
elseif(commentType=="private")then
|
||||
skipNextFunction = true
|
||||
elseif(commentType=="protected")then
|
||||
if func then
|
||||
func.protected = true
|
||||
end
|
||||
elseif(commentType=="shortDescription")then
|
||||
-- skip
|
||||
elseif(commentType=="property")then
|
||||
local propertyName, propertyType, propertyDesc = content:match("^%s*([%w_]+)%s+([%w_]+)%s*(.*)$")
|
||||
if propertyName then
|
||||
class.fields[propertyName] = {type=propertyType, desc=propertyDesc:gsub("^%S+%s*", "") or ""}
|
||||
propertyName = propertyName:sub(1,1):upper() .. propertyName:sub(2)
|
||||
class.functions[class.class..":get" .. propertyName] = {params={{name="self", type=class.class, desc="self"}}, returns={{type=propertyType, desc=propertyDesc or ""}}, desc="Gets the value of the " .. propertyName .. " property.\n"}
|
||||
class.functions[class.class..":set" .. propertyName] = {params={{name="self", type=class.class, desc="self"}, {name=propertyName, type=propertyType, desc=propertyDesc:gsub("^%S+%s*", "") or ""}}, returns={}, desc="Sets the value of the " .. propertyName .. " property.\n"}
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
if not skipNextFunction then
|
||||
local functionName = getFunctionName(line)
|
||||
if functionName then
|
||||
if func and hasBlockContent(func) then
|
||||
class.functions[functionName] = func
|
||||
end
|
||||
func = {params={}, returns={}, desc=""}
|
||||
end
|
||||
else
|
||||
skipNextFunction = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
if(class.class)then
|
||||
fileContent[class.class] = class
|
||||
end
|
||||
return fileContent
|
||||
end
|
||||
|
||||
local function generateLuaLS(finalContent)
|
||||
local output = {"---@meta\n\n"}
|
||||
|
||||
for filepath, block in pairs(finalContent) do
|
||||
if block.class then
|
||||
if(block.parent~=nil)then
|
||||
table.insert(output, string.format("---@class %s : %s\n", block.class, block.parent))
|
||||
else
|
||||
table.insert(output, string.format("---@class %s\n", block.class))
|
||||
end
|
||||
for k,v in pairs(block.fields)do
|
||||
table.insert(output, string.format("---@field %s %s %s\n", k, v.type, v.desc))
|
||||
end
|
||||
table.insert(output, string.format("local %s = {}\n\n", block.class))
|
||||
|
||||
for funcName, funcData in pairs(block.functions) do
|
||||
if funcData.desc~="" then
|
||||
table.insert(output, string.format("---%s", funcData.desc))
|
||||
end
|
||||
if(funcData.protected)then
|
||||
table.insert(output, string.format("---This function is protected und should not be called outside of basalt, however you can overwrite it if you know what you're doing.\n"))
|
||||
end
|
||||
for _, param in ipairs(funcData.params) do
|
||||
table.insert(output, string.format("---@param %s %s %s\n", (param.optional and param.name.."?" or param.name), param.type, param.desc))
|
||||
end
|
||||
for _, ret in ipairs(funcData.returns) do
|
||||
table.insert(output, string.format("---@return %s %s\n", ret.type, ret.desc))
|
||||
end
|
||||
if(funcData.protected)then
|
||||
table.insert(output, string.format("---@protected\n"))
|
||||
end
|
||||
|
||||
local paramNames = {}
|
||||
for _, param in ipairs(funcData.params) do
|
||||
table.insert(paramNames, param.name)
|
||||
end
|
||||
|
||||
table.insert(output, string.format("function %s(%s) end\n\n",
|
||||
funcName,
|
||||
table.concat(paramNames, ", ")))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(output)
|
||||
end
|
||||
|
||||
local function mergeTables(t1, t2)
|
||||
local merged = {}
|
||||
for k, v in pairs(t1) do
|
||||
merged[k] = v
|
||||
end
|
||||
for k, v in pairs(t2) do
|
||||
if type(v) == "table" and type(merged[k]) == "table" then
|
||||
merged[k] = mergeTables(merged[k], v)
|
||||
else
|
||||
merged[k] = v
|
||||
end
|
||||
end
|
||||
return merged
|
||||
end
|
||||
|
||||
local log = require(".Basalt2/src/log")
|
||||
local function parseFiles(files)
|
||||
local finalContent = {}
|
||||
for k,v in pairs(files)do
|
||||
local fileContent = parseFile(v)
|
||||
if fileContent then
|
||||
finalContent = mergeTables(finalContent, fileContent)
|
||||
end
|
||||
end
|
||||
|
||||
local lualsContent = generateLuaLS(finalContent)
|
||||
local outFile = fs.open("LuaLS.lua", "w")
|
||||
if outFile then
|
||||
outFile.write(lualsContent)
|
||||
outFile.close()
|
||||
end
|
||||
end
|
||||
|
||||
if _G.fs then
|
||||
parseFiles(getFilesInCC(args[1]))
|
||||
else
|
||||
parseFiles(getFilesInLua(args[1]))
|
||||
end
|
||||
Reference in New Issue
Block a user