mirror of
https://github.com/0x5eal/luau-unzip.git
synced 2025-04-04 06:30:53 +01:00
feat: implement MD document generation for project documentation
This commit is contained in:
parent
4ad9806ccc
commit
c86855ca0c
5 changed files with 386 additions and 0 deletions
20
.lune/generator.luau
Normal file
20
.lune/generator.luau
Normal file
|
@ -0,0 +1,20 @@
|
|||
--> Generate documentation for this project
|
||||
|
||||
local Moonwave = require("./util/generator/moonwave")
|
||||
local Generator = require("./util/generator/generator")
|
||||
local Markdown = require("./util/generator/markdown")
|
||||
|
||||
Generator.removeLegacyFiles()
|
||||
|
||||
local packageCommentJson = Moonwave.extractCommentsIntoJson()
|
||||
|
||||
for _, classDocumentation in packageCommentJson do
|
||||
local documentPath = Generator.writeClassName(classDocumentation.name)
|
||||
local documentContent = Markdown.generateMarkdownDocumentFor(classDocumentation)
|
||||
|
||||
print(`Writing document '{classDocumentation.name}' to '{documentPath}', size: {string.len(documentContent)}`)
|
||||
|
||||
Generator.writeClassContent(documentPath, documentContent)
|
||||
end
|
||||
|
||||
return {}
|
51
.lune/util/generator/generator.luau
Normal file
51
.lune/util/generator/generator.luau
Normal file
|
@ -0,0 +1,51 @@
|
|||
local fs = require("@lune/fs")
|
||||
local net = require("@lune/net")
|
||||
|
||||
local Generator = {}
|
||||
|
||||
function Generator.removeLegacyFiles()
|
||||
if fs.isDir("docs/classes") then
|
||||
fs.removeDir("docs/classes")
|
||||
end
|
||||
|
||||
fs.writeDir("docs/classes")
|
||||
end
|
||||
|
||||
function Generator.writeClassName(className: string)
|
||||
local classPath = string.split(className, ".")
|
||||
local fullPath = "docs/classes/"
|
||||
|
||||
local fileName = table.remove(classPath, #classPath) :: string
|
||||
local netSafeFileName = net.urlEncode(fileName, false)
|
||||
|
||||
for index, path in classPath do
|
||||
if not fs.isDir(fullPath .. path) then
|
||||
fs.writeDir(fullPath .. path)
|
||||
end
|
||||
|
||||
fullPath ..= `{path}/`
|
||||
end
|
||||
|
||||
fs.writeFile(fullPath .. `{netSafeFileName}.md`, ``)
|
||||
return fullPath .. `{netSafeFileName}.md`
|
||||
end
|
||||
|
||||
function Generator.writeClassContent(classPath: string, classContent: string)
|
||||
local pathComponents = string.split(classPath, "/")
|
||||
local path = "."
|
||||
|
||||
table.remove(pathComponents, #pathComponents)
|
||||
|
||||
for _, component in pathComponents do
|
||||
warn(component)
|
||||
if not fs.isDir(`{path}/{component}`) then
|
||||
fs.writeDir(`{path}/{component}`)
|
||||
|
||||
path ..= `/{component}`
|
||||
end
|
||||
end
|
||||
|
||||
fs.writeFile(classPath, classContent)
|
||||
end
|
||||
|
||||
return Generator
|
191
.lune/util/generator/markdown.luau
Normal file
191
.lune/util/generator/markdown.luau
Normal file
|
@ -0,0 +1,191 @@
|
|||
local Moonwave = require("moonwave")
|
||||
local Types = require("types")
|
||||
|
||||
local Markdown = {}
|
||||
|
||||
local function comment(source)
|
||||
return `[//]: # ({source})\n`
|
||||
end
|
||||
|
||||
local function newline()
|
||||
return `\n`
|
||||
end
|
||||
|
||||
local function h1(source)
|
||||
return `# {source}\n\n`
|
||||
end
|
||||
|
||||
local function h2(source)
|
||||
return `## {source}\n\n`
|
||||
end
|
||||
|
||||
local function h3(source)
|
||||
return `### {source}\n\n`
|
||||
end
|
||||
|
||||
local function input(source)
|
||||
return `{source}\n`
|
||||
end
|
||||
|
||||
local function separator()
|
||||
return `---\n`
|
||||
end
|
||||
|
||||
local function property(name: string, type: string)
|
||||
return `<LuaProperty name="{name}" type="{type}" />`
|
||||
end
|
||||
|
||||
local function getReadableParamList(proto: Moonwave.FunctionData)
|
||||
local readableList = " "
|
||||
|
||||
if #proto.params == 0 then
|
||||
return ""
|
||||
end
|
||||
|
||||
for index, paramObject in proto.params do
|
||||
readableList ..= `\`{paramObject.name}\` {Types.parseLuauType(paramObject.lua_type, true)}` .. (index == #proto.params and ` ` or `, `)
|
||||
end
|
||||
|
||||
return readableList
|
||||
end
|
||||
|
||||
local function getReadableReturnsList(proto: Moonwave.FunctionData)
|
||||
local readableList = " "
|
||||
|
||||
if #proto.returns == 0 then
|
||||
return Types.parseLuauType("nil")
|
||||
end
|
||||
|
||||
for index, returnObject in proto.returns do
|
||||
readableList ..= `{Types.parseLuauType(returnObject.lua_type, true)}` .. (index == #proto.returns and ` ` or `, `)
|
||||
end
|
||||
|
||||
return readableList
|
||||
end
|
||||
|
||||
local function frontmatter(source: {
|
||||
name: string,
|
||||
description: string,
|
||||
order: number,
|
||||
})
|
||||
return `---\ntitle: {source.name}\ndescription: {source.description}\nsidebar:\n order: {source.order}\n collapsed: true\n---`
|
||||
end
|
||||
|
||||
function Markdown.generateMarkdownDocumentFor(classDocumentation: Moonwave.DataExportObject)
|
||||
local markdownFile = ``
|
||||
|
||||
local className = classDocumentation.name:gmatch("%S+%.(%S+)")() or classDocumentation.name
|
||||
local classDescription = classDocumentation.desc
|
||||
local classProperties = classDocumentation.properties
|
||||
|
||||
local classMethods = Moonwave.getFunctionsOfFunctionType(classDocumentation.functions, "method")
|
||||
local classFunctions = Moonwave.getFunctionsOfFunctionType(classDocumentation.functions, "static")
|
||||
|
||||
local sizeOfClassProperties = #classProperties
|
||||
|
||||
local sizeOfClassMethods = #classMethods
|
||||
local sizeOfClassFunctions = #classFunctions
|
||||
|
||||
local order = #string.split(classDocumentation.name, ".")
|
||||
|
||||
markdownFile ..= frontmatter({
|
||||
name = className,
|
||||
description = `luau-unzip docs for {className}.`,
|
||||
order = order,
|
||||
})
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
markdownFile ..= comment(
|
||||
`This file was automatically @generated from moonwave comments using a script. Please do not edit by hand.`
|
||||
)
|
||||
markdownFile ..= comment(`To edit this documentation, make changes to the main luau-unzip repo.`)
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
|
||||
markdownFile ..= comment(`----- DOCUMENT INTRODUCTION ----- `)
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
markdownFile ..= h1(className)
|
||||
|
||||
markdownFile ..= input(classDescription)
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
markdownFile ..= comment(`----- DOCUMENT PROPERTIES ----- `)
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
markdownFile ..= h2(`Properties`)
|
||||
|
||||
if sizeOfClassProperties > 0 then
|
||||
for _, prop in classProperties do
|
||||
markdownFile ..= h3(prop.name)
|
||||
markdownFile ..= property(`{className}.{prop.name}`, prop.lua_type)
|
||||
markdownFile ..= newline()
|
||||
|
||||
if prop.desc ~= "" then
|
||||
markdownFile ..= separator()
|
||||
markdownFile ..= input(prop.desc)
|
||||
end
|
||||
end
|
||||
else
|
||||
markdownFile ..= input(`The {className} instance has no set properties!`)
|
||||
end
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
markdownFile ..= comment(`----- DOCUMENT METHODS ----- `)
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
markdownFile ..= h2(`Methods`)
|
||||
|
||||
if sizeOfClassMethods > 0 then
|
||||
for _, method in classMethods do
|
||||
markdownFile ..= h3(method.name)
|
||||
markdownFile ..= input(
|
||||
`> {className}:{method.name}({getReadableParamList(method)}) -> {getReadableReturnsList(method)}`
|
||||
)
|
||||
|
||||
if method.desc then
|
||||
markdownFile ..= newline()
|
||||
markdownFile ..= input(method.desc)
|
||||
end
|
||||
end
|
||||
else
|
||||
markdownFile ..= input(`The {className} instance has no set methods!`)
|
||||
end
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
markdownFile ..= comment(`----- DOCUMENT FUNCTIONS ----- `)
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
markdownFile ..= h2(`Functions`)
|
||||
|
||||
if sizeOfClassFunctions > 0 then
|
||||
for _, func in classFunctions do
|
||||
markdownFile ..= h3(func.name)
|
||||
markdownFile ..= input(
|
||||
`> {className}.{func.name}({getReadableParamList(func)}) -> {getReadableReturnsList(func)}`
|
||||
)
|
||||
|
||||
if func.desc then
|
||||
markdownFile ..= newline()
|
||||
markdownFile ..= input(func.desc)
|
||||
end
|
||||
end
|
||||
else
|
||||
markdownFile ..= input(`The {className} instance has no set functions!`)
|
||||
end
|
||||
|
||||
markdownFile ..= newline()
|
||||
|
||||
return markdownFile
|
||||
end
|
||||
|
||||
return Markdown
|
85
.lune/util/generator/moonwave.luau
Normal file
85
.lune/util/generator/moonwave.luau
Normal file
|
@ -0,0 +1,85 @@
|
|||
local process = require("@lune/process")
|
||||
local serde = require("@lune/serde")
|
||||
|
||||
local Moonwave = {}
|
||||
|
||||
function Moonwave.getFunctionsOfFunctionType(inputArray: { any }, functionType: string)
|
||||
local resultArray = {}
|
||||
|
||||
for _, functionObject in inputArray do
|
||||
if functionObject.function_type == functionType then
|
||||
table.insert(resultArray, functionObject)
|
||||
end
|
||||
end
|
||||
|
||||
return resultArray
|
||||
end
|
||||
|
||||
function Moonwave.extractCommentsIntoJson(): moonwaveDataExportArray
|
||||
local moonwaveExtractResult = process.spawn("./moonwave-extractor", {
|
||||
"extract",
|
||||
"lib",
|
||||
})
|
||||
|
||||
if not moonwaveExtractResult.ok then
|
||||
print(moonwaveExtractResult.stderr)
|
||||
|
||||
return process.exit(1)
|
||||
else
|
||||
local moonwaveData = serde.decode("json", moonwaveExtractResult.stdout)
|
||||
|
||||
return moonwaveData
|
||||
end
|
||||
end
|
||||
|
||||
export type PropertyData = {
|
||||
name: string,
|
||||
desc: string,
|
||||
lua_type: string,
|
||||
source: {
|
||||
line: number,
|
||||
path: string,
|
||||
},
|
||||
}
|
||||
|
||||
export type FunctionData = {
|
||||
name: string,
|
||||
desc: string,
|
||||
since: string?,
|
||||
unreleased: boolean?,
|
||||
source: {
|
||||
path: string,
|
||||
line: number,
|
||||
},
|
||||
function_type: "method" | "static",
|
||||
returns: {
|
||||
{
|
||||
desc: string,
|
||||
lua_type: string,
|
||||
}
|
||||
},
|
||||
params: {
|
||||
{
|
||||
name: string,
|
||||
desc: string,
|
||||
lua_type: string,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export type DataExportObject = {
|
||||
name: string,
|
||||
functions: { FunctionData },
|
||||
source: { path: string, line: number },
|
||||
properties: { PropertyData },
|
||||
inherited: { [string]: { functions: { FunctionData }, properties: { PropertyData } } }?,
|
||||
desc: string,
|
||||
types: unknown,
|
||||
tags: { string }?
|
||||
}
|
||||
|
||||
export type moonwaveDataExportArray = {
|
||||
DataExportObject
|
||||
}
|
||||
|
||||
return Moonwave
|
39
.lune/util/generator/types.luau
Normal file
39
.lune/util/generator/types.luau
Normal file
|
@ -0,0 +1,39 @@
|
|||
local Types = {}
|
||||
|
||||
local mappedLuauDataTypes = {
|
||||
-- generic Roblox datatypes
|
||||
[{ "nil" }] = "https://www.lua.org/pil/2.1.html",
|
||||
[{ "boolean", "bool" }] = "https://www.lua.org/pil/2.2.html",
|
||||
[{ "number" }] = "https://www.lua.org/pil/2.3.html",
|
||||
[{ "string" }] = "https://www.lua.org/pil/2.4.html",
|
||||
[{ "table" }] = "https://www.lua.org/pil/2.5.html",
|
||||
[{ "tuple", "..." }] = "https://www.lua.org/pil/5.1.html",
|
||||
[{ "userdata", "proxy" }] = "https://www.lua.org/pil/28.1.html",
|
||||
}
|
||||
|
||||
function Types.parseLuauType(luaType: string, escapeBracket: boolean?)
|
||||
luaType = luaType == "" and "any" or luaType
|
||||
|
||||
if string.sub(luaType, 1, 1) == "!" then
|
||||
local path = string.split(string.sub(luaType, 2), "/")
|
||||
local fileName = path[1]
|
||||
|
||||
return `[{fileName}](/Classes/{table.concat(path, "/")})`
|
||||
end
|
||||
|
||||
local luaTypeCheck = string.gsub(string.lower(luaType), "%W", "")
|
||||
|
||||
if escapeBracket then
|
||||
luaType = string.gsub(luaType, "{", "\\{")
|
||||
end
|
||||
|
||||
for queryTable, apiUrl in mappedLuauDataTypes do
|
||||
if table.find(queryTable, luaTypeCheck) then
|
||||
return `[{luaType}]({apiUrl})`
|
||||
end
|
||||
end
|
||||
|
||||
return luaType
|
||||
end
|
||||
|
||||
return Types
|
Loading…
Add table
Reference in a new issue