Module:Database report/generate docs

--[[

Lua module for generating wikitext documentation from LuaDoc comments.

This module parses LuaDoc-style comments from Lua modules and generates
comprehensive wikitext documentation with function signatures, parameters,
return values, usage examples, and more.

Usage from Lua:
local generator = DocGenerator:new()
local wikitext = generator:generateDocumentation(moduleContent)

Usage from wikitext:
{{#invoke:DocGenerator|generate|module=ModuleName}}

]]

local DocGenerator = {}
DocGenerator.__index = DocGenerator

--- Initialize a new documentation generator.
-- Creates a new DocGenerator instance for parsing LuaDoc comments.
-- @return DocGenerator A new DocGenerator instance
-- @usage local generator = DocGenerator:new()
function DocGenerator:new()
    local obj = {
        functions = {},
        module_info = {},
        current_function = nil
    }
    setmetatable(obj, self)
    return obj
end

--- Parse LuaDoc comments from module content.
-- Extracts function documentation, parameters, return values, and usage examples.
-- @param content string The Lua module content to parse
-- @return DocGenerator Returns self for method chaining
-- @usage generator:parseModule(content)
function DocGenerator:parseModule(content)
    self.functions = {}
    self.module_info = {}
    self.current_function = nil
    
    local lines = {}
    for line in content:gmatch("[^\r\n]+") do
        table.insert(lines, line)
    end
    
    local i = 1
    while i <= #lines do
        local line = lines[i]
        
        -- Parse module-level documentation
        if line:match("^%-%-%[%[") and not self.current_function then
            i = self:parseModuleDoc(lines, i)
        -- Parse function documentation
        elseif line:match("^%-%-%-") then
            i = self:parseFunctionDoc(lines, i)
        -- Parse function definition
        elseif line:match("^function") then
            i = self:parseFunctionDef(lines, i)
        else
            i = i + 1
        end
    end
    
    return self
end

--- Parse module-level documentation.
-- Extracts general module information and description.
-- @param lines table Array of lines from the module
-- @param start_index number Starting line index
-- @return number Next line index to process
function DocGenerator:parseModuleDoc(lines, start_index)
    local i = start_index
    local doc_lines = {}
    
    -- Collect documentation until closing ]]
    while i <= #lines do
        local line = lines[i]
        table.insert(doc_lines, line)
        
        if line:match("%]%]") then
            break
        end
        i = i + 1
    end
    
    -- Parse the documentation
    local doc_text = table.concat(doc_lines, "\n")
    self.module_info.description = self:extractDescription(doc_text)
    self.module_info.usage = self:extractUsage(doc_text)
    
    return i + 1
end

--- Parse function documentation block.
-- Extracts detailed function documentation including parameters and examples.
-- @param lines table Array of lines from the module
-- @param start_index number Starting line index
-- @return number Next line index to process
function DocGenerator:parseFunctionDoc(lines, start_index)
    local i = start_index
    local doc_lines = {}
    
    -- Collect all documentation lines
    while i <= #lines and lines[i]:match("^%-%-") do
        table.insert(doc_lines, lines[i])
        i = i + 1
    end
    
    -- Parse the documentation
    local doc_text = table.concat(doc_lines, "\n")
    local func_info = self:parseFunctionDocText(doc_text)
    
    if func_info then
        self.current_function = func_info
    end
    
    return i
end

--- Parse function definition.
-- Extracts function name and signature information.
-- @param lines table Array of lines from the module
-- @param start_index number Starting line index
-- @return number Next line index to process
function DocGenerator:parseFunctionDef(lines, start_index)
    local line = lines[start_index]
    local func_name = self:extractFunctionName(line)
    
    if func_name and self.current_function then
        self.current_function.name = func_name
        self.current_function.signature = self:extractFunctionSignature(line)
        table.insert(self.functions, self.current_function)
        self.current_function = nil
    end
    
    return start_index + 1
end

--- Parse function documentation text.
-- Extracts all documentation elements from a function's doc block.
-- @param doc_text string The documentation text to parse
-- @return table|nil Function information table or nil if not a function doc
function DocGenerator:parseFunctionDocText(doc_text)
    -- Check if this is a function documentation block
    if not doc_text:match("^%-%-%-") then
        return nil
    end
    
    local func_info = {
        name = nil,
        signature = nil,
        description = "",
        parameters = {},
        return_value = nil,
        usage_examples = {},
        raises = {},
        see_also = {}
    }
    
    -- Extract description (first line after ---)
    func_info.description = self:extractDescription(doc_text)
    
    -- Extract parameters with improved regex
    for param_line in doc_text:gmatch("@param%s+([^\r\n]+)") do
        local name, type, description = param_line:match("^([^%s]+)%s+([^%s]+)%s+(.+)")
        if name and type and description then
            table.insert(func_info.parameters, {
                name = name,
                type = type,
                description = description
            })
        end
    end
    
    -- Extract return value with improved regex
    local return_match = doc_text:match("@return%s+([^\r\n]+)")
    if return_match then
        local type, description = return_match:match("^([^%s]+)%s+(.+)")
        if type and description then
            func_info.return_value = {
                type = type,
                description = description
            }
        end
    end
    
    -- Extract usage examples
    for example in doc_text:gmatch("@usage%s+([^\r\n]+)") do
        table.insert(func_info.usage_examples, example)
    end
    
    -- Extract raises information
    for raise in doc_text:gmatch("@raise%s+([^\r\n]+)") do
        table.insert(func_info.raises, raise)
    end
    
    return func_info
end

--- Extract description from documentation text.
-- @param doc_text string Documentation text
-- @return string Extracted description
function DocGenerator:extractDescription(doc_text)
    local lines = {}
    for line in doc_text:gmatch("[^\r\n]+") do
        table.insert(lines, line)
    end
    
    local description_lines = {}
    local in_description = false
    
    for _, line in ipairs(lines) do
        if line:match("^%-%-%-") then
            in_description = true
            local desc = line:gsub("^%-%-%-%s*", "")
            if desc ~= "" then
                table.insert(description_lines, desc)
            end
        elseif in_description and line:match("^%-%-%s*@") then
            break
        elseif in_description and line:match("^%-%-%s*[^@]") then
            local desc = line:gsub("^%-%-%s*", "")
            table.insert(description_lines, desc)
        end
    end
    
    return table.concat(description_lines, " ")
end

--- Extract usage information from module documentation.
-- @param doc_text string Module documentation text
-- @return string Extracted usage information
function DocGenerator:extractUsage(doc_text)
    local usage_match = doc_text:match("@usage ([^}]+)")
    if usage_match then
        return usage_match:gsub("^%s*", ""):gsub("%s*$", "")
    end
    return ""
end

--- Extract function name from function definition line.
-- @param line string Function definition line
-- @return string|nil Function name or nil if not found
function DocGenerator:extractFunctionName(line)
    local match = line:match("function%s+([^:]+):([^%(]+)")
    if match then
        return match .. ":" .. line:match("function%s+[^:]+:([^%(]+)")
    end
    
    match = line:match("function%s+([^%(]+)")
    if match then
        return match
    end
    
    return nil
end

--- Extract function signature from function definition line.
-- @param line string Function definition line
-- @return string Function signature
function DocGenerator:extractFunctionSignature(line)
    return line:gsub("^%s*", "")
end

--- Generate wikitext documentation.
-- Creates comprehensive wikitext documentation from parsed information.
-- @return string Generated wikitext documentation
-- @usage local wikitext = generator:generateWikitext()
function DocGenerator:generateWikitext()
    local wikitext = {}
    
    -- -- Module header
    -- table.insert(wikitext, "== Module Documentation ==")
    -- table.insert(wikitext, "")
    
    -- if self.module_info.description then
    --     table.insert(wikitext, self.module_info.description)
    --     table.insert(wikitext, "")
    -- end
    
    -- if self.module_info.usage and self.module_info.usage ~= "" then
    --     table.insert(wikitext, "=== Usage ===")
    --     table.insert(wikitext, "")
    --     table.insert(wikitext, self:generateCodeBlock(self.module_info.usage))
    --     table.insert(wikitext, "")
    -- end
    
    -- Method documentation
    if #self.functions > 0 then
        -- table.insert(wikitext, "== Usage ==")
        -- table.insert(wikitext, "")
        
        for _, func in ipairs(self.functions) do
            table.insert(wikitext, self:generateFunctionWikitext(func))
            table.insert(wikitext, "")
        end
    end
    
    return table.concat(wikitext, "\n")
end

function DocGenerator:generateCodeBlock(content) 
	return mw.getCurrentFrame():preprocess("<syntaxhighlight lang=lua>" .. content .. "</syntaxhighlight>")
end

--- Generate wikitext for a single function.
-- @param func table Function information
-- @return string Function wikitext documentation
function DocGenerator:generateFunctionWikitext(func)
    local wikitext = {}
    
    -- Function header
    table.insert(wikitext, "=== " .. (func.name or "Unknown function") .. " ===")
    table.insert(wikitext, "")
    
    -- Description
    if func.description and func.description ~= "" then
        table.insert(wikitext, func.description)
        table.insert(wikitext, "")
    end
    
    -- Function signature
    if func.signature then
        table.insert(wikitext, "'''Signature:'''")
        table.insert(wikitext, "")
        table.insert(wikitext, self:generateCodeBlock(func.signature))
        table.insert(wikitext, "")
    end
    
    -- Parameters
    if #func.parameters > 0 then
        table.insert(wikitext, "'''Parameters:'''")
        table.insert(wikitext, "")
        for _, param in ipairs(func.parameters) do
            table.insert(wikitext, "* '''" .. param.name .. "''' (" .. param.type .. ") - " .. param.description)
        end
        table.insert(wikitext, "")
    end
    
    -- Return value
    if func.return_value then
        table.insert(wikitext, "'''Returns:'''")
        table.insert(wikitext, "")
        table.insert(wikitext, "* (" .. func.return_value.type .. ") " .. func.return_value.description)
        table.insert(wikitext, "")
    end
    
    -- Usage examples
    if #func.usage_examples > 0 then
        table.insert(wikitext, "'''Usage examples:'''")
        table.insert(wikitext, "")
        for _, example in ipairs(func.usage_examples) do
            table.insert(wikitext, self:generateCodeBlock(example))
        end
    end
    
    -- Raises
    if #func.raises > 0 then
        table.insert(wikitext, "'''Raises:'''")
        table.insert(wikitext, "")
        for _, raise in ipairs(func.raises) do
            table.insert(wikitext, "* " .. raise)
        end
    end
    
    return table.concat(wikitext, "\n")
end

--- Generate documentation for a specific module.
-- Convenience method to parse and generate documentation in one call.
-- @param module_content string The module content to document
-- @return string Generated wikitext documentation
-- @usage local docs = generator:documentModule(content)
function DocGenerator:documentModule(module_content)
    self:parseModule(module_content)
    return self:generateWikitext()
end

-- MediaWiki interface functions

--- Main entry point for MediaWiki invocation.
-- @param frame table The frame object from MediaWiki
-- @return string Generated documentation
function DocGenerator.main(frame)
    local generator = DocGenerator:new()
    
    -- Get module name from parameters
    local module_name = frame.args.module or frame.args[1]
    if not module_name then
        return "Error: No module specified. Use |module=ModuleName"
    end
    
    local module_code = mw.title.new('Module:' .. module_name).content
    
    return generator:documentModule(module_code)
end

--- Generate documentation from file content.
-- Alternative entry point that takes file content directly.
-- @param frame table The frame object from MediaWiki
-- @return string Generated documentation
function DocGenerator.fromFile(frame)
    local generator = DocGenerator:new()
    local content = frame.args.content or frame.args[1]
    
    if not content then
        return "Error: No content provided. Use |content=... or provide content as first parameter."
    end
    
    return generator:documentModule(content)
end

return DocGenerator

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.