Small Docs test
This commit is contained in:
112
.github/workflows/main.yml
vendored
112
.github/workflows/main.yml
vendored
@@ -14,69 +14,69 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup Lua
|
- name: Setup Lua
|
||||||
uses: leafo/gh-actions-lua@v8
|
uses: leafo/gh-actions-lua@v8
|
||||||
with:
|
with:
|
||||||
luaVersion: "5.4"
|
luaVersion: "5.4"
|
||||||
|
|
||||||
# Step 1: Config Generation
|
# Step 1: Config Generation
|
||||||
- name: Generate Config
|
- name: Generate Config
|
||||||
run: |
|
run: |
|
||||||
lua tools/generate-config.lua
|
lua tools/generate-config.lua
|
||||||
|
|
||||||
# Step 2: Generate LuaLS Definitions
|
# Step 2: Generate LuaLS Definitions
|
||||||
- name: Generate LuaLS
|
- name: Generate LuaLS
|
||||||
run: |
|
run: |
|
||||||
lua tools/generate-annotations.lua src
|
lua tools/generate-annotations.lua src
|
||||||
|
|
||||||
# Step 3: Bundle and Minify
|
# Step 3: Bundle and Minify
|
||||||
- name: Bundle and Minify
|
- name: Bundle and Minify
|
||||||
run: |
|
run: |
|
||||||
mkdir -p release
|
mkdir -p release
|
||||||
lua tools/bundler.lua
|
lua tools/bundler.lua
|
||||||
|
|
||||||
# Step 4: Prepare and Generate Documentation
|
# Step 4: Prepare and Generate Documentation
|
||||||
- name: Prepare docs directory
|
- name: Prepare docs directory
|
||||||
run: |
|
run: |
|
||||||
# Checkout gh-pages branch in a separate directory
|
# Checkout gh-pages branch in a separate directory
|
||||||
git worktree add gh-pages gh-pages
|
git worktree add gh-pages gh-pages
|
||||||
|
|
||||||
# Only clean references directory
|
# Only clean references directory
|
||||||
rm -rf gh-pages/docs/references
|
rm -rf gh-pages/docs/references
|
||||||
mkdir -p gh-pages/docs/references
|
mkdir -p gh-pages/docs/references
|
||||||
|
|
||||||
#- name: Generate Documentation
|
- name: Generate Documentation
|
||||||
# run: |
|
run: |
|
||||||
# lua tools/generate-docs.lua
|
lua tools/generate-docs.lua
|
||||||
|
|
||||||
# cp -r build_docs/docs/references/* gh-pages/docs/references/
|
cp -r build_docs/docs/references/* gh-pages/docs/references/
|
||||||
|
|
||||||
# Step 5: Deploy Documentation
|
# Step 5: Deploy Documentation
|
||||||
- name: Deploy Documentation
|
- name: Deploy Documentation
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
publish_dir: ./gh-pages
|
publish_dir: ./gh-pages
|
||||||
keep_files: true
|
keep_files: true
|
||||||
|
|
||||||
# Step 6: Generate Changelog
|
# Step 6: Generate Changelog
|
||||||
#- name: Generate Changelog
|
#- name: Generate Changelog
|
||||||
# id: changelog
|
# id: changelog
|
||||||
# uses: heinrichreimer/github-changelog-generator-action@v2.3
|
# uses: heinrichreimer/github-changelog-generator-action@v2.3
|
||||||
# with:
|
# with:
|
||||||
# token: ${{ secrets.GITHUB_TOKEN }}
|
# token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
# Step 7: Commit all changes
|
# Step 7: Commit all changes
|
||||||
- name: Commit Changes
|
- name: Commit Changes
|
||||||
run: |
|
run: |
|
||||||
git config --global user.name 'github-actions[bot]'
|
git config --global user.name 'github-actions[bot]'
|
||||||
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
||||||
git add config.lua BasaltLS.lua release/basalt.lua CHANGELOG.md
|
git add config.lua BasaltLS.lua release/basalt.lua CHANGELOG.md
|
||||||
git commit -m "Update config, BasaltLS definitions, bundle and changelog" || exit 0
|
git commit -m "Update config, BasaltLS definitions, bundle and changelog" || exit 0
|
||||||
git push
|
git push
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -8,7 +8,5 @@ testWorkflows
|
|||||||
.vscode
|
.vscode
|
||||||
todo.txt
|
todo.txt
|
||||||
Flexbox2.lua
|
Flexbox2.lua
|
||||||
markdown2.lua
|
markdown.lua
|
||||||
BasaltDoc
|
markdown2.lua
|
||||||
generate-docs.lua
|
|
||||||
io.lua
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
local elementManager = require("elementManager")
|
|
||||||
local VisualElement = elementManager.getElement("VisualElement")
|
|
||||||
local getCenteredPosition = require("libraries/utils").getCenteredPosition
|
|
||||||
---@cofnigDescription The Button is a standard button element with click handling and state management.
|
|
||||||
|
|
||||||
--- The Button is a standard button element with click handling and state management.
|
|
||||||
---@class Button : VisualElement
|
|
||||||
local Button = setmetatable({}, VisualElement)
|
|
||||||
Button.__index = Button
|
|
||||||
|
|
||||||
---@property text string Button Button text
|
|
||||||
Button.defineProperty(Button, "text", {default = "Button", type = "string", canTriggerRender = true})
|
|
||||||
|
|
||||||
Button.defineEvent(Button, "mouse_click")
|
|
||||||
Button.defineEvent(Button, "mouse_up")
|
|
||||||
|
|
||||||
--- @shortDescription Creates a new Button instance
|
|
||||||
--- @return table self The created instance
|
|
||||||
--- @private
|
|
||||||
function Button.new()
|
|
||||||
local self = setmetatable({}, Button):__init()
|
|
||||||
self.class = Button
|
|
||||||
self.set("width", 10)
|
|
||||||
self.set("height", 3)
|
|
||||||
self.set("z", 5)
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Initializes the Button instance
|
|
||||||
--- @shortDescription Initializes the Button instance
|
|
||||||
--- @param props table The properties to initialize the element with
|
|
||||||
--- @param basalt table The basalt instance
|
|
||||||
--- @protected
|
|
||||||
function Button:init(props, basalt)
|
|
||||||
VisualElement.init(self, props, basalt)
|
|
||||||
self.set("type", "Button")
|
|
||||||
end
|
|
||||||
|
|
||||||
--- @shortDescription Renders the Button
|
|
||||||
--- @protected
|
|
||||||
function Button:render()
|
|
||||||
VisualElement.render(self)
|
|
||||||
local text = self.get("text")
|
|
||||||
text = text:sub(1, self.get("width"))
|
|
||||||
local xO, yO = getCenteredPosition(text, self.get("width"), self.get("height"))
|
|
||||||
self:textFg(xO, yO, text, self.get("foreground"))
|
|
||||||
end
|
|
||||||
|
|
||||||
return Button
|
|
||||||
270
tools/BasaltDoc/init.lua
Normal file
270
tools/BasaltDoc/init.lua
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
local BasaltDoc = {}
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
local docsPath = fs.getDir(args[2])
|
||||||
|
local defaultPath = package.path
|
||||||
|
local format = "path;/path/?.lua;/path/?/init.lua;"
|
||||||
|
local main = format:gsub("path", docsPath)
|
||||||
|
package.path = main.."rom/?;"..defaultPath
|
||||||
|
|
||||||
|
local ok1, classParser = pcall(require, "parsers.classParser")
|
||||||
|
|
||||||
|
local ok2, functionParser = pcall(require, "parsers.functionParser")
|
||||||
|
|
||||||
|
local ok3, propertyParser = pcall(require, "parsers.propertyParser")
|
||||||
|
|
||||||
|
local ok4, eventParser = pcall(require, "parsers.eventParser")
|
||||||
|
|
||||||
|
local ok6, globalParser = pcall(require, "parsers.globalParser")
|
||||||
|
|
||||||
|
local ok5, markdownGenerator = pcall(require, "utils.markdownGenerator")
|
||||||
|
|
||||||
|
BasaltDoc.annotationHandlers = {}
|
||||||
|
|
||||||
|
function BasaltDoc.registerAnnotation(tag, handler)
|
||||||
|
BasaltDoc.annotationHandlers[tag] = handler
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- Standard Annotation Handlers
|
||||||
|
----------------------------------------------------------------
|
||||||
|
BasaltDoc.registerAnnotation("@param", function(target, args)
|
||||||
|
if target.type == "function" then
|
||||||
|
local paramName, optional, paramType, paramDesc = args:match("([%w_]+)(%??)[%s]*([%w_|]+)[%s]*(.*)")
|
||||||
|
if paramName then
|
||||||
|
table.insert(target.params, {
|
||||||
|
name = paramName,
|
||||||
|
type = paramType or "any",
|
||||||
|
description = paramDesc or "",
|
||||||
|
optional = optional == "?"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@return", function(target, args)
|
||||||
|
if target.type == "function" then
|
||||||
|
local returnType, returnName, returnDesc = args:match("([%w_|]+)[%s]+([%w_]+)[%s]+(.*)")
|
||||||
|
if returnType then
|
||||||
|
table.insert(target.returns, {
|
||||||
|
type = returnType,
|
||||||
|
name = returnName or "",
|
||||||
|
description = returnDesc or ""
|
||||||
|
})
|
||||||
|
else
|
||||||
|
table.insert(target.returns, {
|
||||||
|
type = args:match("([%w_|]+)") or "any",
|
||||||
|
name = "",
|
||||||
|
description = args:match("[%w_|]+[%s]+(.*)" ) or ""
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@returns", function(target, args)
|
||||||
|
BasaltDoc.annotationHandlers["@return"](target, args)
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@usage", function(target, args)
|
||||||
|
if not target.usage then target.usage = {} end
|
||||||
|
table.insert(target.usage, args)
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@example", function(target, args)
|
||||||
|
if not target.examples then target.examples = {} end
|
||||||
|
table.insert(target.examples, args)
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@see", function(target, args)
|
||||||
|
if not target.see then target.see = {} end
|
||||||
|
table.insert(target.see, args)
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@since", function(target, args)
|
||||||
|
target.since = args
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@deprecated", function(target, args)
|
||||||
|
target.deprecated = args ~= "" and args or true
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@private", function(target, args)
|
||||||
|
target.visibility = "private"
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@protected", function(target, args)
|
||||||
|
target.visibility = "protected"
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@configDescription", function(target, args)
|
||||||
|
if target.type == "class" then
|
||||||
|
target.configDescription = args
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@shortDescription", function(target, args)
|
||||||
|
if target.type == "function" then
|
||||||
|
target.shortDescription = args
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@run", function(target, args)
|
||||||
|
if not target.run then target.run = {} end
|
||||||
|
table.insert(target.run, args)
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@title", function(target, args)
|
||||||
|
target.title = args
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@skipFunctionList", function(target, args)
|
||||||
|
target.skipFunctionList = true
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@skipPropertyList", function(target, args)
|
||||||
|
target.skipPropertyList = true
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@skipDetailedFunctionList", function(target, args)
|
||||||
|
target.skipDetailedFunctionList = true
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@skip", function(target, args)
|
||||||
|
target.skip = true
|
||||||
|
end)
|
||||||
|
|
||||||
|
BasaltDoc.registerAnnotation("@globalDescription", function(target, args)
|
||||||
|
if args and args ~= "" then
|
||||||
|
target.description = args
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if ok1 then classParser.setHandlers(BasaltDoc.annotationHandlers) end
|
||||||
|
if ok2 then functionParser.setHandlers(BasaltDoc.annotationHandlers) end
|
||||||
|
if ok3 then propertyParser.setHandlers(BasaltDoc.annotationHandlers) end
|
||||||
|
if ok4 then eventParser.setHandlers(BasaltDoc.annotationHandlers) end
|
||||||
|
if ok6 then globalParser.setHandlers(BasaltDoc.annotationHandlers) end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- Main Parser
|
||||||
|
----------------------------------------------------------------
|
||||||
|
function BasaltDoc.parse(content)
|
||||||
|
local ast = { classes = {}, global = nil }
|
||||||
|
|
||||||
|
local rawLines = {}
|
||||||
|
for line in content:gmatch("([^\r\n]*)\r?\n?") do
|
||||||
|
table.insert(rawLines, line)
|
||||||
|
end
|
||||||
|
|
||||||
|
local lines = {}
|
||||||
|
local i = 1
|
||||||
|
while i <= #rawLines do
|
||||||
|
local line = rawLines[i]
|
||||||
|
if line:match("@globalDescription") then
|
||||||
|
local globalAnnotations = {line}
|
||||||
|
i = i + 1
|
||||||
|
if i <= #rawLines and rawLines[i]:match("%-%-?%[%[") then
|
||||||
|
i = i + 1
|
||||||
|
while i <= #rawLines and not rawLines[i]:match("%]%]") do
|
||||||
|
table.insert(globalAnnotations, "--- " .. rawLines[i])
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
if i <= #rawLines and rawLines[i]:match("%]%]") then
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
if #globalAnnotations > 0 and ok6 then
|
||||||
|
local global = globalParser.parse(globalAnnotations, table.concat(globalAnnotations, "\n"))
|
||||||
|
ast.global = global
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(lines, line)
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local annotationBuffer = {}
|
||||||
|
local currentClass = nil
|
||||||
|
local firstTag = nil
|
||||||
|
|
||||||
|
local blockStartTags = {
|
||||||
|
["@class"] = true,
|
||||||
|
["@property"] = true,
|
||||||
|
["@event"] = true,
|
||||||
|
["@skip"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
while i <= #lines do
|
||||||
|
local line = lines[i]
|
||||||
|
if line:match("^%-%-%-?") then
|
||||||
|
table.insert(annotationBuffer, line)
|
||||||
|
if not firstTag then
|
||||||
|
local tag = line:match("@%S+")
|
||||||
|
if tag and blockStartTags[tag] then
|
||||||
|
firstTag = tag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
elseif #annotationBuffer > 0 then
|
||||||
|
local nextLine = lines[i]
|
||||||
|
local skip = false
|
||||||
|
if nextLine and nextLine:match("^function") and currentClass and ok2 then
|
||||||
|
local fn = functionParser.parse(annotationBuffer, nextLine)
|
||||||
|
if fn then
|
||||||
|
table.insert(currentClass.functions, fn)
|
||||||
|
end
|
||||||
|
skip = true
|
||||||
|
elseif firstTag then
|
||||||
|
if firstTag == "@class" and ok1 then
|
||||||
|
local class = classParser.parse(annotationBuffer, table.concat(annotationBuffer, "\n"))
|
||||||
|
if class and not class.skip then
|
||||||
|
table.insert(ast.classes, class)
|
||||||
|
currentClass = class
|
||||||
|
end
|
||||||
|
elseif firstTag == "@property" and currentClass and ok3 then
|
||||||
|
local prop = propertyParser.parse(annotationBuffer, table.concat(annotationBuffer, "\n"))
|
||||||
|
if prop then
|
||||||
|
table.insert(currentClass.properties, prop)
|
||||||
|
end
|
||||||
|
elseif firstTag == "@event" and currentClass and ok4 then
|
||||||
|
local evt = eventParser.parse(annotationBuffer, table.concat(annotationBuffer, "\n"))
|
||||||
|
if evt then
|
||||||
|
table.insert(currentClass.events, evt)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if skip then i = i + 1 end
|
||||||
|
annotationBuffer = {}
|
||||||
|
firstTag = nil
|
||||||
|
i = i + 1
|
||||||
|
else
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #annotationBuffer > 0 and firstTag then
|
||||||
|
if firstTag == "@class" and ok1 then
|
||||||
|
local class = classParser.parse(annotationBuffer, table.concat(annotationBuffer, "\n"))
|
||||||
|
if class and not class.skip then
|
||||||
|
table.insert(ast.classes, class)
|
||||||
|
currentClass = class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return ast
|
||||||
|
end
|
||||||
|
|
||||||
|
function BasaltDoc.generateMarkdown(ast)
|
||||||
|
if ok5 then
|
||||||
|
local result = markdownGenerator.generate(ast)
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
package.path = defaultPath
|
||||||
|
|
||||||
|
return BasaltDoc
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# ldoc-markdown-parser
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
`ldoc-markdown-parser` is a simple and extensible Lua documentation parser that converts Lua documentation comments into Markdown format. It supports both single-line and multi-line comments, making it easy to document your Lua code in a structured way.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
- Extracts single-line and multi-line comments from Lua files.
|
|
||||||
- Parses custom tags such as `@property`, `@shortDescription`, `@param`, and `@return`.
|
|
||||||
- Converts extracted comments and parsed tags into Markdown format.
|
|
||||||
- Easy to extend and customize for additional tags or formatting options.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
To install the `ldoc-markdown-parser`, clone the repository and navigate to the project directory:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone <repository-url>
|
|
||||||
cd ldoc-markdown-parser
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
To use the parser, run the `main.lua` file with the Lua interpreter, providing the path to the Lua file you want to parse:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
lua src/main.lua path/to/your/lua_file.lua
|
|
||||||
```
|
|
||||||
|
|
||||||
The output will be generated in Markdown format and can be found in the specified output directory.
|
|
||||||
|
|
||||||
## Example
|
|
||||||
An example Lua file can be found in the `examples/input/example.lua`, and the expected output Markdown file is located in `examples/output/example.md`.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
Contributions are welcome! Please feel free to submit a pull request or open an issue for any enhancements or bug fixes.
|
|
||||||
|
|
||||||
## License
|
|
||||||
This project is licensed under the MIT License. See the LICENSE file for more details.
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
local FunctionParser = {}
|
|
||||||
|
|
||||||
--- Check if a block represents a function
|
|
||||||
function FunctionParser.canParse(block)
|
|
||||||
return block.context and block.context.type == "function"
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Parse a complete function documentation block
|
|
||||||
function FunctionParser.parse(block)
|
|
||||||
local functionDoc = {
|
|
||||||
type = "function",
|
|
||||||
name = block.context.name,
|
|
||||||
shortDescription = nil,
|
|
||||||
params = {},
|
|
||||||
returns = {},
|
|
||||||
visibility = "public", -- default
|
|
||||||
context = block.context,
|
|
||||||
content = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, line in ipairs(block.comments) do
|
|
||||||
-- Parse shortDescription
|
|
||||||
local shortDesc = line:match("^%-*%s*@shortDescription%s+(.*)$")
|
|
||||||
if shortDesc then
|
|
||||||
functionDoc.shortDescription = shortDesc
|
|
||||||
|
|
||||||
-- Parse param
|
|
||||||
elseif line:match("^%-*%s*@param") then
|
|
||||||
local paramName, paramType, paramDesc = line:match("^%-*%s*@param%s+(%S+)%s+(%S+)%s+(.*)$")
|
|
||||||
if paramName then
|
|
||||||
table.insert(functionDoc.params, {
|
|
||||||
name = paramName,
|
|
||||||
type = paramType,
|
|
||||||
description = paramDesc or ""
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Parse return
|
|
||||||
elseif line:match("^%-*%s*@return") then
|
|
||||||
local returnType, returnName, returnDesc = line:match("^%-*%s*@return%s+(%S+)%s+(%S+)%s+(.*)$")
|
|
||||||
if returnType then
|
|
||||||
table.insert(functionDoc.returns, {
|
|
||||||
type = returnType,
|
|
||||||
name = returnName or "",
|
|
||||||
description = returnDesc or ""
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Parse visibility
|
|
||||||
elseif line:match("^%-*%s*@private%s*$") then
|
|
||||||
functionDoc.visibility = "private"
|
|
||||||
elseif line:match("^%-*%s*@protected%s*$") then
|
|
||||||
functionDoc.visibility = "protected"
|
|
||||||
|
|
||||||
-- Regular content
|
|
||||||
else
|
|
||||||
table.insert(functionDoc.content, line)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return functionDoc
|
|
||||||
end
|
|
||||||
|
|
||||||
return FunctionParser
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
local CommentExtractor = {}
|
|
||||||
|
|
||||||
--- Extracts comment blocks that belong together
|
|
||||||
function CommentExtractor.extractBlocks(lines)
|
|
||||||
local blocks = {}
|
|
||||||
local currentBlock = {
|
|
||||||
comments = {},
|
|
||||||
codeContext = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
local i = 1
|
|
||||||
while i <= #lines do
|
|
||||||
local line = lines[i]
|
|
||||||
local trimmed = line:match("^%s*(.-)%s*$")
|
|
||||||
|
|
||||||
-- Check if this is a comment line
|
|
||||||
if trimmed:match("^%-%-%-") or trimmed:match("^%-%-") then
|
|
||||||
table.insert(currentBlock.comments, trimmed)
|
|
||||||
elseif #currentBlock.comments > 0 then
|
|
||||||
-- We have comments, now look for the code that follows
|
|
||||||
local codeLineIndex = CommentExtractor.findNextCodeLine(lines, i)
|
|
||||||
if codeLineIndex then
|
|
||||||
local codeLine = lines[codeLineIndex]:match("^%s*(.-)%s*$")
|
|
||||||
currentBlock.codeContext = CommentExtractor.analyzeCode(codeLine, codeLineIndex)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Save this block and start a new one
|
|
||||||
table.insert(blocks, currentBlock)
|
|
||||||
currentBlock = {comments = {}, codeContext = nil}
|
|
||||||
end
|
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle remaining comments
|
|
||||||
if #currentBlock.comments > 0 then
|
|
||||||
table.insert(blocks, currentBlock)
|
|
||||||
end
|
|
||||||
|
|
||||||
return blocks
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Find the next non-empty code line
|
|
||||||
function CommentExtractor.findNextCodeLine(lines, startIndex)
|
|
||||||
for i = startIndex, #lines do
|
|
||||||
local trimmed = lines[i]:match("^%s*(.-)%s*$")
|
|
||||||
if trimmed ~= "" and not trimmed:match("^%-%-") then
|
|
||||||
return i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Analyze what kind of code this is
|
|
||||||
function CommentExtractor.analyzeCode(codeLine, lineNumber)
|
|
||||||
-- Function patterns
|
|
||||||
if codeLine:match("^function%s+([%w%.%:]+)") then
|
|
||||||
local name = codeLine:match("^function%s+([%w%.%:]+)")
|
|
||||||
return {type = "function", name = name, line = codeLine, lineNumber = lineNumber}
|
|
||||||
end
|
|
||||||
|
|
||||||
if codeLine:match("^local%s+function%s+([%w%.%:]+)") then
|
|
||||||
local name = codeLine:match("^local%s+function%s+([%w%.%:]+)")
|
|
||||||
return {type = "function", name = name, line = codeLine, lineNumber = lineNumber}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Class/variable patterns
|
|
||||||
if codeLine:match("^local%s+([%w_]+)%s*=%s*setmetatable") then
|
|
||||||
local name = codeLine:match("^local%s+([%w_]+)%s*=")
|
|
||||||
return {type = "class", name = name, line = codeLine, lineNumber = lineNumber}
|
|
||||||
end
|
|
||||||
|
|
||||||
if codeLine:match("^local%s+([%w_]+)%s*=") then
|
|
||||||
local name = codeLine:match("^local%s+([%w_]+)%s*=")
|
|
||||||
return {type = "variable", name = name, line = codeLine, lineNumber = lineNumber}
|
|
||||||
end
|
|
||||||
|
|
||||||
return {type = "unknown", name = "unknown", line = codeLine, lineNumber = lineNumber}
|
|
||||||
end
|
|
||||||
|
|
||||||
return CommentExtractor
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
local CommentExtractor = require("parser.comment_extractor")
|
|
||||||
local TagParser = require("parser.tag_parser")
|
|
||||||
local MarkdownGenerator = require("parser.markdown_generator")
|
|
||||||
|
|
||||||
local Parser = {}
|
|
||||||
|
|
||||||
--- Extract comments and generate markdown
|
|
||||||
function Parser.extractComments(content)
|
|
||||||
local lines = {}
|
|
||||||
for line in content:gmatch("[^\r\n]+") do
|
|
||||||
table.insert(lines, line)
|
|
||||||
end
|
|
||||||
return CommentExtractor.extractBlocks(lines)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Generate markdown from comment blocks
|
|
||||||
function Parser.generateMarkdown(commentBlocks)
|
|
||||||
local markdown = {}
|
|
||||||
|
|
||||||
-- Parse each block and generate markdown
|
|
||||||
for _, block in ipairs(commentBlocks) do
|
|
||||||
local tags = TagParser.parseAllTags(block.comments)
|
|
||||||
local blockMarkdown = MarkdownGenerator.generateBlock(block, tags)
|
|
||||||
if blockMarkdown and blockMarkdown ~= "" then
|
|
||||||
table.insert(markdown, blockMarkdown)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return table.concat(markdown, "\n\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
return Parser
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
local MarkdownGenerator = {}
|
|
||||||
|
|
||||||
--- Generate markdown for a block
|
|
||||||
function MarkdownGenerator.generateBlock(block, tags)
|
|
||||||
if not block.codeContext then
|
|
||||||
return MarkdownGenerator.generateStandaloneComment(tags)
|
|
||||||
end
|
|
||||||
|
|
||||||
if block.codeContext.type == "function" then
|
|
||||||
return MarkdownGenerator.generateFunction(block.codeContext, tags)
|
|
||||||
elseif block.codeContext.type == "class" then
|
|
||||||
return MarkdownGenerator.generateClass(block.codeContext, tags)
|
|
||||||
elseif block.codeContext.type == "variable" then
|
|
||||||
return MarkdownGenerator.generateVariable(block.codeContext, tags)
|
|
||||||
else
|
|
||||||
return MarkdownGenerator.generateGeneric(block.codeContext, tags)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Generate markdown for function
|
|
||||||
function MarkdownGenerator.generateFunction(context, tags)
|
|
||||||
local md = {}
|
|
||||||
|
|
||||||
table.insert(md, string.format("### %s", context.name))
|
|
||||||
table.insert(md, "")
|
|
||||||
|
|
||||||
if tags.shortDescription then
|
|
||||||
table.insert(md, tags.shortDescription)
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
if #tags.description > 0 then
|
|
||||||
table.insert(md, table.concat(tags.description, " "))
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
if #tags.params > 0 then
|
|
||||||
table.insert(md, "**Parameters:**")
|
|
||||||
for _, param in ipairs(tags.params) do
|
|
||||||
table.insert(md, string.format("- `%s` (%s): %s", param.name, param.dataType, param.description))
|
|
||||||
end
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
if #tags.returns > 0 then
|
|
||||||
table.insert(md, "**Returns:**")
|
|
||||||
for _, ret in ipairs(tags.returns) do
|
|
||||||
table.insert(md, string.format("- `%s` (%s): %s", ret.name, ret.dataType, ret.description))
|
|
||||||
end
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
if tags.visibility ~= "public" then
|
|
||||||
table.insert(md, string.format("**Visibility:** %s", tags.visibility))
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
return table.concat(md, "\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Generate markdown for class
|
|
||||||
function MarkdownGenerator.generateClass(context, tags)
|
|
||||||
local md = {}
|
|
||||||
|
|
||||||
table.insert(md, string.format("## Class: %s", context.name))
|
|
||||||
if tags.class and tags.class.parent then
|
|
||||||
table.insert(md, string.format("*Extends: %s*", tags.class.parent))
|
|
||||||
end
|
|
||||||
table.insert(md, "")
|
|
||||||
|
|
||||||
if tags.shortDescription then
|
|
||||||
table.insert(md, tags.shortDescription)
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
if #tags.description > 0 then
|
|
||||||
table.insert(md, table.concat(tags.description, " "))
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
return table.concat(md, "\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Generate markdown for standalone comments or properties
|
|
||||||
function MarkdownGenerator.generateStandaloneComment(tags)
|
|
||||||
local md = {}
|
|
||||||
|
|
||||||
if #tags.properties > 0 then
|
|
||||||
for _, prop in ipairs(tags.properties) do
|
|
||||||
table.insert(md, string.format("**Property:** `%s` (%s) - %s", prop.name, prop.dataType, prop.description))
|
|
||||||
end
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
if #tags.description > 0 then
|
|
||||||
table.insert(md, table.concat(tags.description, " "))
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
return table.concat(md, "\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Generate markdown for variables
|
|
||||||
function MarkdownGenerator.generateVariable(context, tags)
|
|
||||||
local md = {}
|
|
||||||
|
|
||||||
table.insert(md, string.format("### %s", context.name))
|
|
||||||
table.insert(md, "")
|
|
||||||
|
|
||||||
if tags.shortDescription then
|
|
||||||
table.insert(md, tags.shortDescription)
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
if #tags.description > 0 then
|
|
||||||
table.insert(md, table.concat(tags.description, " "))
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
return table.concat(md, "\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Generate markdown for generic code
|
|
||||||
function MarkdownGenerator.generateGeneric(context, tags)
|
|
||||||
local md = {}
|
|
||||||
|
|
||||||
table.insert(md, string.format("### %s", context.name))
|
|
||||||
table.insert(md, "")
|
|
||||||
|
|
||||||
if tags.shortDescription then
|
|
||||||
table.insert(md, tags.shortDescription)
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
if #tags.description > 0 then
|
|
||||||
table.insert(md, table.concat(tags.description, " "))
|
|
||||||
table.insert(md, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
return table.concat(md, "\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
return MarkdownGenerator
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
local TagParser = {}
|
|
||||||
|
|
||||||
--- Parse all tags from a list of comment lines
|
|
||||||
function TagParser.parseAllTags(commentLines)
|
|
||||||
local tags = {
|
|
||||||
shortDescription = nil,
|
|
||||||
description = {},
|
|
||||||
params = {},
|
|
||||||
returns = {},
|
|
||||||
visibility = "public",
|
|
||||||
properties = {},
|
|
||||||
class = nil,
|
|
||||||
other = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, line in ipairs(commentLines) do
|
|
||||||
local parsed = TagParser.parseSingleLine(line)
|
|
||||||
if parsed then
|
|
||||||
TagParser.addToTags(tags, parsed)
|
|
||||||
else
|
|
||||||
-- Regular description line
|
|
||||||
local desc = line:match("^%-*%s*(.+)$")
|
|
||||||
if desc and not desc:match("^@") then
|
|
||||||
table.insert(tags.description, desc)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return tags
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Parse a single comment line for tags
|
|
||||||
function TagParser.parseSingleLine(line)
|
|
||||||
-- @shortDescription
|
|
||||||
local shortDesc = line:match("^%-*%s*@shortDescription%s+(.+)$")
|
|
||||||
if shortDesc then
|
|
||||||
return {type = "shortDescription", value = shortDesc}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- @param name type description
|
|
||||||
local paramName, paramType, paramDesc = line:match("^%-*%s*@param%s+(%S+)%s+(%S+)%s*(.*)$")
|
|
||||||
if paramName then
|
|
||||||
return {
|
|
||||||
type = "param",
|
|
||||||
name = paramName,
|
|
||||||
dataType = paramType,
|
|
||||||
description = paramDesc or ""
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- @return type name description
|
|
||||||
local returnType, returnName, returnDesc = line:match("^%-*%s*@return%s+(%S+)%s+(%S+)%s*(.*)$")
|
|
||||||
if returnType then
|
|
||||||
return {
|
|
||||||
type = "return",
|
|
||||||
dataType = returnType,
|
|
||||||
name = returnName or "",
|
|
||||||
description = returnDesc or ""
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- @property name type description
|
|
||||||
local propName, propType, propDesc = line:match("^%-*%s*@property%s+(%S+)%s+(%S+)%s*(.*)$")
|
|
||||||
if propName then
|
|
||||||
return {
|
|
||||||
type = "property",
|
|
||||||
name = propName,
|
|
||||||
dataType = propType,
|
|
||||||
description = propDesc or ""
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- @class name : parent
|
|
||||||
local className, parentClass = line:match("^%-*%s*@class%s+(%S+)%s*:%s*(%S+)")
|
|
||||||
if not className then
|
|
||||||
className = line:match("^%-*%s*@class%s+(%S+)")
|
|
||||||
end
|
|
||||||
if className then
|
|
||||||
return {
|
|
||||||
type = "class",
|
|
||||||
name = className,
|
|
||||||
parent = parentClass or nil
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Visibility tags
|
|
||||||
if line:match("^%-*%s*@private%s*$") then
|
|
||||||
return {type = "visibility", value = "private"}
|
|
||||||
end
|
|
||||||
|
|
||||||
if line:match("^%-*%s*@protected%s*$") then
|
|
||||||
return {type = "visibility", value = "protected"}
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Add parsed tag to the tags collection
|
|
||||||
function TagParser.addToTags(tags, parsed)
|
|
||||||
if parsed.type == "shortDescription" then
|
|
||||||
tags.shortDescription = parsed.value
|
|
||||||
elseif parsed.type == "param" then
|
|
||||||
table.insert(tags.params, parsed)
|
|
||||||
elseif parsed.type == "return" then
|
|
||||||
table.insert(tags.returns, parsed)
|
|
||||||
elseif parsed.type == "property" then
|
|
||||||
table.insert(tags.properties, parsed)
|
|
||||||
elseif parsed.type == "class" then
|
|
||||||
tags.class = parsed
|
|
||||||
elseif parsed.type == "visibility" then
|
|
||||||
tags.visibility = parsed.value
|
|
||||||
else
|
|
||||||
table.insert(tags.other, parsed)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return TagParser
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
local TagParserRegistry = {}
|
|
||||||
|
|
||||||
local tagParsers = {}
|
|
||||||
local blockParsers = {}
|
|
||||||
|
|
||||||
--- Register a new tag parser (for individual tags like @param, @return)
|
|
||||||
function TagParserRegistry.registerTag(tagName, parser)
|
|
||||||
tagParsers[tagName] = parser
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Register a new block parser (for complete blocks like functions, classes)
|
|
||||||
function TagParserRegistry.registerBlock(blockType, parser)
|
|
||||||
blockParsers[blockType] = parser
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get a specific tag parser
|
|
||||||
function TagParserRegistry.getTag(tagName)
|
|
||||||
return tagParsers[tagName]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get a specific block parser
|
|
||||||
function TagParserRegistry.getBlock(blockType)
|
|
||||||
return blockParsers[blockType]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get all registered tag parsers
|
|
||||||
function TagParserRegistry.getAllTags()
|
|
||||||
return tagParsers
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get all registered block parsers
|
|
||||||
function TagParserRegistry.getAllBlocks()
|
|
||||||
return blockParsers
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Auto-load all parsers
|
|
||||||
local function loadAllParsers()
|
|
||||||
-- Load tag parsers (individual tags)
|
|
||||||
local tagParsersList = {"param", "return", "property", "private", "protected", "shortDescription"}
|
|
||||||
for _, parserName in ipairs(tagParsersList) do
|
|
||||||
local success, parser = pcall(require, "parser.tag_parsers." .. parserName)
|
|
||||||
if success then
|
|
||||||
TagParserRegistry.registerTag(parserName, parser)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Load block parsers (complete documentation blocks)
|
|
||||||
local blockParsersList = {"function", "class", "property_definition"}
|
|
||||||
for _, parserName in ipairs(blockParsersList) do
|
|
||||||
local success, parser = pcall(require, "parser.block_parsers." .. parserName)
|
|
||||||
if success then
|
|
||||||
TagParserRegistry.registerBlock(parserName, parser)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
loadAllParsers()
|
|
||||||
|
|
||||||
return TagParserRegistry
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
local PropertyParser = {}
|
|
||||||
|
|
||||||
--- Parse @property tag
|
|
||||||
--- Example: ---@property text string Button Button text
|
|
||||||
function PropertyParser.parse(line)
|
|
||||||
local pattern = "^%-*%s*@property%s+(%S+)%s+(%S+)%s+(.*)$"
|
|
||||||
local name, dataType, description = line:match(pattern)
|
|
||||||
|
|
||||||
if name and dataType then
|
|
||||||
return {
|
|
||||||
type = "property",
|
|
||||||
name = name,
|
|
||||||
dataType = dataType,
|
|
||||||
description = description or ""
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
return PropertyParser
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
local ShortDescriptionParser = {}
|
|
||||||
|
|
||||||
--- Parse @shortDescription tag
|
|
||||||
--- Example: --- @shortDescription Creates a new Button instance
|
|
||||||
function ShortDescriptionParser.parse(line)
|
|
||||||
local pattern = "^%-*%s*@shortDescription%s+(.*)$"
|
|
||||||
local description = line:match(pattern)
|
|
||||||
|
|
||||||
if description then
|
|
||||||
return {
|
|
||||||
type = "shortDescription",
|
|
||||||
description = description
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
return ShortDescriptionParser
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
local fileReader = {}
|
|
||||||
|
|
||||||
--- Read file content
|
|
||||||
--- @param filePath string Path to the file
|
|
||||||
--- @return string|nil content File content or nil if error
|
|
||||||
--- @return string|nil error Error message if any
|
|
||||||
function fileReader.readFile(filePath)
|
|
||||||
local file = io.open(filePath, "r")
|
|
||||||
if not file then
|
|
||||||
return nil, "Could not open file: " .. filePath
|
|
||||||
end
|
|
||||||
|
|
||||||
local content = file:read("*all")
|
|
||||||
file:close()
|
|
||||||
|
|
||||||
return content, nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Write content to file
|
|
||||||
--- @param filePath string Path to the file
|
|
||||||
--- @param content string Content to write
|
|
||||||
--- @return string|nil error Error message if any
|
|
||||||
function fileReader.writeFile(filePath, content)
|
|
||||||
local file = io.open(filePath, "w")
|
|
||||||
if not file then
|
|
||||||
return "Could not open file for writing: " .. filePath
|
|
||||||
end
|
|
||||||
|
|
||||||
file:write(content)
|
|
||||||
file:close()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
return fileReader
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
local string_utils = require("utils.string_utils")
|
|
||||||
|
|
||||||
local utils = {}
|
|
||||||
|
|
||||||
-- Re-export string utilities
|
|
||||||
utils.trim = string_utils.trim
|
|
||||||
utils.is_empty = string_utils.is_empty
|
|
||||||
utils.starts_with = string_utils.starts_with
|
|
||||||
utils.ends_with = string_utils.ends_with
|
|
||||||
utils.split = string_utils.split
|
|
||||||
|
|
||||||
function utils.isClassMethod(name)
|
|
||||||
return name:sub(1, 1):upper() == name:sub(1, 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
return utils
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
local string_utils = {}
|
|
||||||
|
|
||||||
function string_utils.trim(s)
|
|
||||||
return s:match("^%s*(.-)%s*$")
|
|
||||||
end
|
|
||||||
|
|
||||||
function string_utils.is_empty(s)
|
|
||||||
return s == nil or s == ""
|
|
||||||
end
|
|
||||||
|
|
||||||
function string_utils.starts_with(s, prefix)
|
|
||||||
return s:sub(1, #prefix) == prefix
|
|
||||||
end
|
|
||||||
|
|
||||||
function string_utils.ends_with(s, suffix)
|
|
||||||
return s:sub(-#suffix) == suffix
|
|
||||||
end
|
|
||||||
|
|
||||||
function string_utils.split(s, delimiter)
|
|
||||||
local result = {}
|
|
||||||
for match in (s..delimiter):gmatch("(.-)"..delimiter) do
|
|
||||||
table.insert(result, match)
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
return string_utils
|
|
||||||
34
tools/BasaltDoc/parsers/classParser.lua
Normal file
34
tools/BasaltDoc/parsers/classParser.lua
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
local helper = require("utils.helper")
|
||||||
|
local logger = require("utils.logger")
|
||||||
|
local classParser = {}
|
||||||
|
|
||||||
|
function classParser.parse(annotations, line)
|
||||||
|
local classLine = helper.findAnnotationLine(annotations, "class")
|
||||||
|
if not classLine then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local name, extends = classLine:match("^%-%-%-?%s*@class%s*([%w_%.]+)%s*:?%s*([%w_%.]*)")
|
||||||
|
|
||||||
|
local class = {
|
||||||
|
type = "class",
|
||||||
|
name = name,
|
||||||
|
extends = extends ~= "" and extends or nil,
|
||||||
|
description = nil,
|
||||||
|
properties = {},
|
||||||
|
events = {},
|
||||||
|
functions = {},
|
||||||
|
skip = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if classParser.handlers then
|
||||||
|
helper.applyAnnotations(annotations, class, classParser.handlers)
|
||||||
|
end
|
||||||
|
|
||||||
|
return class
|
||||||
|
end
|
||||||
|
|
||||||
|
function classParser.setHandlers(handlers)
|
||||||
|
classParser.handlers = handlers
|
||||||
|
end
|
||||||
|
|
||||||
|
return classParser
|
||||||
37
tools/BasaltDoc/parsers/eventParser.lua
Normal file
37
tools/BasaltDoc/parsers/eventParser.lua
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
local helper = require("utils.helper")
|
||||||
|
local eventParser = {}
|
||||||
|
|
||||||
|
function eventParser.parse(annotations, line)
|
||||||
|
local eventLine = helper.findAnnotationLine(annotations, "event")
|
||||||
|
if not eventLine then return nil end
|
||||||
|
local content = table.concat(annotations, " ")
|
||||||
|
local name, params, desc = eventLine:match("^%-%-%-?%s*@event%s*([%w_]+)%s*({[^}]*})%s*(.*)")
|
||||||
|
|
||||||
|
if not name then
|
||||||
|
name, desc = eventLine:match("^%-%-%-?%s*@event%s*([%w_]+)%s+(.*)")
|
||||||
|
params = "{}"
|
||||||
|
end
|
||||||
|
|
||||||
|
if not name then
|
||||||
|
print("Warning: Could not parse @event annotation: " .. eventLine)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local evt = {
|
||||||
|
type = "event",
|
||||||
|
name = name,
|
||||||
|
params = params or "{}",
|
||||||
|
description = desc or ""
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.applyAnnotations(annotations, evt, eventParser.handlers)
|
||||||
|
|
||||||
|
return evt
|
||||||
|
end
|
||||||
|
|
||||||
|
function eventParser.setHandlers(handlers)
|
||||||
|
eventParser.handlers = handlers
|
||||||
|
end
|
||||||
|
|
||||||
|
return eventParser
|
||||||
|
|
||||||
48
tools/BasaltDoc/parsers/functionParser.lua
Normal file
48
tools/BasaltDoc/parsers/functionParser.lua
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
local helper = require("utils.helper")
|
||||||
|
local functionParser = {}
|
||||||
|
|
||||||
|
function functionParser.parse(annotations, line)
|
||||||
|
local name = line:match("^function%s+([%w_%.]+[:.]?[%w_]+)") or line:match("^function%s+([%w_]+)")
|
||||||
|
if not name then
|
||||||
|
print("Warning: Could not extract function name from line: " .. line)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local f = {
|
||||||
|
type = "function",
|
||||||
|
name = name,
|
||||||
|
description = nil,
|
||||||
|
shortDescription = nil,
|
||||||
|
params = {},
|
||||||
|
returns = {},
|
||||||
|
visibility = "public"
|
||||||
|
}
|
||||||
|
|
||||||
|
if functionParser.handlers then
|
||||||
|
helper.applyAnnotations(annotations, f, functionParser.handlers)
|
||||||
|
end
|
||||||
|
|
||||||
|
local funcName = line:match("function ([%w_%.]+)")
|
||||||
|
if funcName then
|
||||||
|
if funcName:find(":") then
|
||||||
|
f.name = funcName:match(":([%w_]+)")
|
||||||
|
elseif funcName:find("%.") then
|
||||||
|
f.name = funcName:match("%.([%w_]+)")
|
||||||
|
else
|
||||||
|
f.name = funcName
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if line:match("function [%w_%.]+:") then
|
||||||
|
f.static = false
|
||||||
|
else
|
||||||
|
f.static = true
|
||||||
|
end
|
||||||
|
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
|
||||||
|
function functionParser.setHandlers(handlers)
|
||||||
|
functionParser.handlers = handlers
|
||||||
|
end
|
||||||
|
|
||||||
|
return functionParser
|
||||||
21
tools/BasaltDoc/parsers/globalParser.lua
Normal file
21
tools/BasaltDoc/parsers/globalParser.lua
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
local helper = require("utils.helper")
|
||||||
|
local logger = require("utils.logger")
|
||||||
|
local globalParser = {}
|
||||||
|
|
||||||
|
function globalParser.parse(annotations, line)
|
||||||
|
local global = {
|
||||||
|
description = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if globalParser.handlers then
|
||||||
|
helper.applyAnnotations(annotations, global, globalParser.handlers)
|
||||||
|
end
|
||||||
|
return global
|
||||||
|
end
|
||||||
|
|
||||||
|
function globalParser.setHandlers(handlers)
|
||||||
|
globalParser.handlers = handlers
|
||||||
|
end
|
||||||
|
|
||||||
|
return globalParser
|
||||||
|
|
||||||
30
tools/BasaltDoc/parsers/propertyParser.lua
Normal file
30
tools/BasaltDoc/parsers/propertyParser.lua
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
local helper = require("utils.helper")
|
||||||
|
local propertyParser = {}
|
||||||
|
|
||||||
|
function propertyParser.parse(annotations, line)
|
||||||
|
local propLine = helper.findAnnotationLine(annotations, "property")
|
||||||
|
if not propLine then return nil end
|
||||||
|
local content = table.concat(annotations, " ")
|
||||||
|
local name, type, default, desc = propLine:match("^%-%-%-?%s*@property%s*([%w_]+)%s+([%w_|%[%]]+)%s+([^%s]+)%s*(.*)")
|
||||||
|
if not name then
|
||||||
|
print("Warning: Could not parse @property annotation: " .. propLine)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local prop = {
|
||||||
|
type = "property",
|
||||||
|
name = name,
|
||||||
|
propType = type or "any",
|
||||||
|
default = default or "nil",
|
||||||
|
description = desc or ""
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.applyAnnotations(annotations, prop, propertyParser.handlers)
|
||||||
|
|
||||||
|
return prop
|
||||||
|
end
|
||||||
|
|
||||||
|
function propertyParser.setHandlers(handlers)
|
||||||
|
propertyParser.handlers = handlers
|
||||||
|
end
|
||||||
|
|
||||||
|
return propertyParser
|
||||||
59
tools/BasaltDoc/utils/helper.lua
Normal file
59
tools/BasaltDoc/utils/helper.lua
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
local helper = {}
|
||||||
|
|
||||||
|
function helper.applyAnnotations(annotations, target, handlers)
|
||||||
|
local i = 1
|
||||||
|
while i <= #annotations do
|
||||||
|
local ann = annotations[i]
|
||||||
|
|
||||||
|
local tag, args = ann:match("^%-%-%-?%s*(@%S+)%s*(.*)")
|
||||||
|
if tag then
|
||||||
|
if args == ">" then
|
||||||
|
local multiArgs = ""
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
while i <= #annotations do
|
||||||
|
local nextAnn = annotations[i]
|
||||||
|
local nextTag = nextAnn:match("^%-%-%-?%s*(@%S+)")
|
||||||
|
if nextTag then
|
||||||
|
i = i - 1
|
||||||
|
break
|
||||||
|
else
|
||||||
|
local content = nextAnn:match("^%-%-%-?%s*(.*)") or nextAnn
|
||||||
|
if multiArgs ~= "" then
|
||||||
|
multiArgs = multiArgs .. "\n" .. content
|
||||||
|
else
|
||||||
|
multiArgs = content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
args = multiArgs
|
||||||
|
end
|
||||||
|
|
||||||
|
if handlers and handlers[tag] then
|
||||||
|
handlers[tag](target, args)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local comment = ann:match("^%-%-%-?%s*(.*)") or ann
|
||||||
|
if comment and not comment:match("^@%S+") then
|
||||||
|
if target.description then
|
||||||
|
target.description = target.description .. "\n" .. comment
|
||||||
|
else
|
||||||
|
target.description = comment
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function helper.findAnnotationLine(annotations, tag)
|
||||||
|
for _, l in ipairs(annotations) do
|
||||||
|
if l:match("@" .. tag) then
|
||||||
|
return l
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return helper
|
||||||
26
tools/BasaltDoc/utils/logger.lua
Normal file
26
tools/BasaltDoc/utils/logger.lua
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
local logger = {}
|
||||||
|
|
||||||
|
local logFile
|
||||||
|
|
||||||
|
function logger.init()
|
||||||
|
if not logFile then
|
||||||
|
logFile = io.open("BasaltDoc/debug_log.txt", "w")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function logger.log(message)
|
||||||
|
if not logFile then logger.init() end
|
||||||
|
if logFile then
|
||||||
|
logFile:write(os.date("%Y-%m-%d %H:%M:%S") .. ": " .. message .. "\n")
|
||||||
|
logFile:flush()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function logger.close()
|
||||||
|
if logFile then
|
||||||
|
logFile:close()
|
||||||
|
logFile = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return logger
|
||||||
222
tools/BasaltDoc/utils/markdownGenerator.lua
Normal file
222
tools/BasaltDoc/utils/markdownGenerator.lua
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
local markdownGenerator = {}
|
||||||
|
|
||||||
|
local function generateFunctionMarkdown(class, functions)
|
||||||
|
local md = {}
|
||||||
|
|
||||||
|
for _, f in ipairs(functions) do
|
||||||
|
local sig = "## "
|
||||||
|
if class.name then
|
||||||
|
sig = sig .. class.name .. (f.static and "." or ":")
|
||||||
|
end
|
||||||
|
sig = sig .. (f.name or "unknown") .. "("
|
||||||
|
|
||||||
|
for i, p in ipairs(f.params) do
|
||||||
|
sig = sig .. p.name
|
||||||
|
if p.optional then sig = sig .. "?" end
|
||||||
|
if i < #f.params then sig = sig .. ", " end
|
||||||
|
end
|
||||||
|
sig = sig .. ")"
|
||||||
|
|
||||||
|
table.insert(md, sig)
|
||||||
|
|
||||||
|
if f.description and f.description ~= "" then
|
||||||
|
table.insert(md, "")
|
||||||
|
table.insert(md, f.description)
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if #f.params > 0 then
|
||||||
|
table.insert(md, "### Parameters")
|
||||||
|
for _, p in ipairs(f.params) do
|
||||||
|
local paramLine = "* `" .. p.name .. "`"
|
||||||
|
if p.optional then paramLine = paramLine .. " *(optional)*" end
|
||||||
|
paramLine = paramLine .. " `" .. p.type .. "`"
|
||||||
|
if p.description and p.description ~= "" then
|
||||||
|
paramLine = paramLine .. " " .. p.description
|
||||||
|
end
|
||||||
|
table.insert(md, paramLine)
|
||||||
|
end
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if #f.returns > 0 then
|
||||||
|
table.insert(md, "### Returns")
|
||||||
|
for _, r in ipairs(f.returns) do
|
||||||
|
local returnLine = "* `" .. r.type .. "`"
|
||||||
|
if r.name and r.name ~= "" then
|
||||||
|
returnLine = returnLine .. " `" .. r.name .. "`"
|
||||||
|
end
|
||||||
|
if r.description and r.description ~= "" then
|
||||||
|
returnLine = returnLine .. " " .. r.description
|
||||||
|
end
|
||||||
|
table.insert(md, returnLine)
|
||||||
|
end
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if f.usage then
|
||||||
|
table.insert(md, "### Usage")
|
||||||
|
table.insert(md, "```lua")
|
||||||
|
for _, usage in ipairs(f.usage) do
|
||||||
|
if usage == "" then
|
||||||
|
table.insert(md, "")
|
||||||
|
else
|
||||||
|
table.insert(md, usage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(md, "```")
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if f.run then
|
||||||
|
table.insert(md, "### Usage (Executable)")
|
||||||
|
table.insert(md, "```lua run")
|
||||||
|
for _, run in ipairs(f.run) do
|
||||||
|
if run == "" then
|
||||||
|
table.insert(md, "")
|
||||||
|
else
|
||||||
|
table.insert(md, run)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(md, "```")
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if f.examples then
|
||||||
|
table.insert(md, "### Examples")
|
||||||
|
for _, example in ipairs(f.examples) do
|
||||||
|
table.insert(md, "```lua")
|
||||||
|
table.insert(md, example)
|
||||||
|
table.insert(md, "```")
|
||||||
|
end
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if f.see then
|
||||||
|
table.insert(md, "### See Also")
|
||||||
|
for _, seeRef in ipairs(f.see) do
|
||||||
|
table.insert(md, "* " .. seeRef)
|
||||||
|
end
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if f.deprecated then
|
||||||
|
table.insert(md, "> **⚠️ Deprecated** " .. (type(f.deprecated) == "string" and f.deprecated or "This function is deprecated"))
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if f.since then
|
||||||
|
table.insert(md, "*Since: " .. f.since .. "*")
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return md
|
||||||
|
end
|
||||||
|
|
||||||
|
function markdownGenerator.generate(ast)
|
||||||
|
local md = {}
|
||||||
|
|
||||||
|
if ast.global then
|
||||||
|
if ast.global.description then
|
||||||
|
table.insert(md, ast.global.description)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local seen = {}
|
||||||
|
for _, class in ipairs(ast.classes) do
|
||||||
|
if not class.skip and not seen[class.name] then
|
||||||
|
seen[class.name] = true
|
||||||
|
local title = class.title or class.name
|
||||||
|
table.insert(md, "# " .. title)
|
||||||
|
if class.description then
|
||||||
|
table.insert(md, "_" .. class.description .. "_")
|
||||||
|
end
|
||||||
|
if class.extends then
|
||||||
|
table.insert(md, "")
|
||||||
|
table.insert(md, "Extends: `" .. class.extends .. "`")
|
||||||
|
end
|
||||||
|
table.insert(md, "")
|
||||||
|
|
||||||
|
if not class.skipPropertyList and #class.properties > 0 then
|
||||||
|
table.insert(md, "## Properties")
|
||||||
|
table.insert(md, "")
|
||||||
|
table.insert(md, "|Property|Type|Default|Description|")
|
||||||
|
table.insert(md, "|---|---|---|---|")
|
||||||
|
for _, p in ipairs(class.properties) do
|
||||||
|
table.insert(md, string.format("|%s|%s|%s|%s|",
|
||||||
|
p.name or "",
|
||||||
|
p.propType or "any",
|
||||||
|
p.default or "nil",
|
||||||
|
p.description or ""))
|
||||||
|
end
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if #class.events > 0 then
|
||||||
|
table.insert(md, "## Events")
|
||||||
|
table.insert(md, "")
|
||||||
|
table.insert(md, "|Event|Parameters|Description|")
|
||||||
|
table.insert(md, "|---|---|---|")
|
||||||
|
for _, e in ipairs(class.events) do
|
||||||
|
local params = e.params or ""
|
||||||
|
if params:match("^{.*}$") then
|
||||||
|
params = params:sub(2, -2)
|
||||||
|
end
|
||||||
|
if params == "" then params = "-" else params = "`" .. params .. "`" end
|
||||||
|
|
||||||
|
table.insert(md, string.format("|%s|%s|%s|",
|
||||||
|
e.name or "", params, e.description or ""))
|
||||||
|
end
|
||||||
|
table.insert(md, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not class.skipFunctionList and #class.functions > 0 then
|
||||||
|
table.insert(md, "## Functions")
|
||||||
|
table.insert(md, "")
|
||||||
|
table.insert(md, "|Method|Returns|Description|")
|
||||||
|
table.insert(md, "|---|---|---|")
|
||||||
|
|
||||||
|
for _, f in ipairs(class.functions) do
|
||||||
|
local methodName = (class.name or "") .. (f.static and "." or ":") .. (f.name or "")
|
||||||
|
|
||||||
|
local anchor = methodName:lower()
|
||||||
|
if #f.params > 0 then
|
||||||
|
for _, p in ipairs(f.params) do
|
||||||
|
anchor = anchor .. "-" .. p.name:lower()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
anchor = anchor:gsub("[^%w%-]", "-")
|
||||||
|
|
||||||
|
local returnType = "-"
|
||||||
|
if #f.returns > 0 then
|
||||||
|
local types = {}
|
||||||
|
for _, r in ipairs(f.returns) do
|
||||||
|
table.insert(types, r.type)
|
||||||
|
end
|
||||||
|
returnType = table.concat(types, ", ")
|
||||||
|
end
|
||||||
|
|
||||||
|
local shortDesc = f.shortDescription or f.description or ""
|
||||||
|
table.insert(md, string.format("|[%s](#%s)|%s|%s|",
|
||||||
|
methodName,
|
||||||
|
anchor,
|
||||||
|
returnType,
|
||||||
|
shortDesc))
|
||||||
|
end
|
||||||
|
table.insert(md, "")
|
||||||
|
|
||||||
|
if not class.skipDetailedFunctionList then
|
||||||
|
local functionMd = generateFunctionMarkdown(class, class.functions)
|
||||||
|
for _, line in ipairs(functionMd) do
|
||||||
|
table.insert(md, line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return md
|
||||||
|
end
|
||||||
|
|
||||||
|
return markdownGenerator
|
||||||
@@ -1,50 +1,99 @@
|
|||||||
|
local arg = arg or {...}
|
||||||
|
|
||||||
local oldPath = package.path
|
local SRC_DIR = arg[1] or 'src'
|
||||||
|
local OUT_DIR = arg[2] or 'docs'
|
||||||
|
|
||||||
local scriptSource = debug.getinfo(1, "S").source
|
local BasaltDoc = require('BasaltDoc')
|
||||||
local scriptDir = nil
|
|
||||||
if scriptSource and scriptSource:sub(1,1) == "@" then
|
local fileSystem
|
||||||
local scriptPath = scriptSource:sub(2)
|
if fs then
|
||||||
scriptDir = scriptPath:match("^(.*)[/\\]") or "."
|
fileSystem = {
|
||||||
|
list = fs.list,
|
||||||
|
combine = fs.combine,
|
||||||
|
isDir = fs.isDir,
|
||||||
|
exists = fs.exists,
|
||||||
|
makeDir = fs.makeDir,
|
||||||
|
open = function(path, mode) return fs.open(path, mode) end,
|
||||||
|
getDir = fs.getDir,
|
||||||
|
readAll = function(file) return file.readAll() end,
|
||||||
|
write = function(file, data) file.write(data) end,
|
||||||
|
close = function(file) file.close() end
|
||||||
|
}
|
||||||
else
|
else
|
||||||
scriptDir = "."
|
local lfs = require("lfs")
|
||||||
|
fileSystem = {
|
||||||
|
list = function(dir)
|
||||||
|
local items = {}
|
||||||
|
for item in lfs.dir(dir) do
|
||||||
|
if item ~= "." and item ~= ".." then
|
||||||
|
table.insert(items, item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return items
|
||||||
|
end,
|
||||||
|
combine = function(a, b) return a .. "/" .. b end,
|
||||||
|
isDir = function(path) return lfs.attributes(path).mode == "directory" end,
|
||||||
|
exists = function(path) return lfs.attributes(path) ~= nil end,
|
||||||
|
makeDir = lfs.mkdir,
|
||||||
|
open = io.open,
|
||||||
|
getDir = function(path) return path:match("(.+)/") end,
|
||||||
|
readAll = function(file) return file:read("*all") end,
|
||||||
|
write = function(file, data) file:write(data) end,
|
||||||
|
close = function(file) file:close() end
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local parserSrc = scriptDir .. "/BasaltDoc/ldoc-markdown-parser/src/"
|
if not fileSystem.exists(OUT_DIR) then
|
||||||
package.path = package.path .. ";" .. parserSrc .. "?.lua;" .. parserSrc .. "?/init.lua"
|
fileSystem.makeDir(OUT_DIR)
|
||||||
local ok, parser = pcall(require, "parser.init")
|
end
|
||||||
local ioAdaptor = require("tools.io")
|
|
||||||
package.path = oldPath
|
|
||||||
|
|
||||||
if not ok or not parser then
|
local function getLuaFiles(dir)
|
||||||
-- try dofile fallback
|
local files = {}
|
||||||
local initPath = parserSrc .. "/parser/init.lua"
|
local list = fileSystem.list(dir)
|
||||||
local ok2, module = pcall(dofile, initPath)
|
for _, item in ipairs(list) do
|
||||||
if ok2 and module then
|
local path = fileSystem.combine(dir, item)
|
||||||
parser = module
|
if fileSystem.isDir(path) then
|
||||||
|
local subFiles = getLuaFiles(path)
|
||||||
|
for _, subFile in ipairs(subFiles) do
|
||||||
|
table.insert(files, subFile)
|
||||||
|
end
|
||||||
|
elseif item:match("%.lua$") then
|
||||||
|
table.insert(files, path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return files
|
||||||
|
end
|
||||||
|
|
||||||
|
local luaFiles = getLuaFiles(SRC_DIR)
|
||||||
|
|
||||||
|
for _, filePath in ipairs(luaFiles) do
|
||||||
|
local file = fileSystem.open(filePath, "r")
|
||||||
|
if file then
|
||||||
|
local content = fileSystem.readAll(file)
|
||||||
|
fileSystem.close(file)
|
||||||
|
|
||||||
|
local ast = BasaltDoc.parse(content)
|
||||||
|
local markdown = BasaltDoc.generateMarkdown(ast)
|
||||||
|
|
||||||
|
local relativePath = filePath:gsub("^" .. SRC_DIR .. "/", ""):gsub("%.lua$", ".md")
|
||||||
|
local outPath = fileSystem.combine(OUT_DIR, relativePath)
|
||||||
|
|
||||||
|
local outDir = fileSystem.getDir(outPath)
|
||||||
|
if outDir and not fileSystem.exists(outDir) then
|
||||||
|
fileSystem.makeDir(outDir)
|
||||||
|
end
|
||||||
|
|
||||||
|
local outFile = fileSystem.open(outPath, "w")
|
||||||
|
if outFile then
|
||||||
|
fileSystem.write(outFile, table.concat(markdown, "\n"))
|
||||||
|
fileSystem.close(outFile)
|
||||||
|
print("Generated: " .. outPath)
|
||||||
|
else
|
||||||
|
print("Error writing: " .. outPath)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
error("Failed to load parser.init via require and dofile (tried: "..tostring(initPath)..")")
|
print("Error reading: " .. filePath)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function processFile(inputFile)
|
print("Documentation generation complete.")
|
||||||
local content = ioAdaptor.readFile(inputFile)
|
|
||||||
if not content then
|
|
||||||
io.stderr:write("Failed to read: " .. tostring(inputFile) .. "\n")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local commentBlocks = parser.extractComments(content)
|
|
||||||
local md = parser.generateMarkdown(commentBlocks)
|
|
||||||
|
|
||||||
local outputFile = "build_docs/docs/references/" .. inputFile:match("^src/(.+)"):gsub("%.lua$", "")
|
|
||||||
ioAdaptor.ensureDirectory(outputFile)
|
|
||||||
ioAdaptor.writeFile(outputFile .. ".md", md)
|
|
||||||
end
|
|
||||||
|
|
||||||
local files = ioAdaptor.listFiles("src", "*.lua")
|
|
||||||
for _, file in ipairs(files) do
|
|
||||||
if not file:match("LuaLS.lua$") then
|
|
||||||
processFile(file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Reference in New Issue
Block a user