Actually, lets just not process the typedefs at all

This commit is contained in:
Filip Tibell 2023-05-14 22:01:44 +02:00
parent 75c79e15e8
commit 0db32ad4c4
No known key found for this signature in database
9 changed files with 153 additions and 199 deletions

View file

@ -35,7 +35,7 @@ export type WriteOptions = {
end end
``` ```
]=] ]=]
export type FS = { return {
--[=[ --[=[
@within FS @within FS
@must_use @must_use
@ -52,7 +52,9 @@ export type FS = {
@param path The path to the file to read @param path The path to the file to read
@return The contents of the file @return The contents of the file
]=] ]=]
readFile: (path: string) -> string, readFile = function(path: string): string
return nil :: any
end,
--[=[ --[=[
@within FS @within FS
@must_use @must_use
@ -68,7 +70,9 @@ export type FS = {
@param path The directory path to search in @param path The directory path to search in
@return A list of files & directories found @return A list of files & directories found
]=] ]=]
readDir: (path: string) -> { string }, readDir = function(path: string): { string }
return {}
end,
--[=[ --[=[
@within FS @within FS
@ -83,7 +87,7 @@ export type FS = {
@param path The path of the file @param path The path of the file
@param contents The contents of the file @param contents The contents of the file
]=] ]=]
writeFile: (path: string, contents: string) -> (), writeFile = function(path: string, contents: string) end,
--[=[ --[=[
@within FS @within FS
@ -97,7 +101,7 @@ export type FS = {
@param path The directory to create @param path The directory to create
]=] ]=]
writeDir: (path: string) -> (), writeDir = function(path: string) end,
--[=[ --[=[
@within FS @within FS
@ -111,7 +115,7 @@ export type FS = {
@param path The file to remove @param path The file to remove
]=] ]=]
removeFile: (path: string) -> (), removeFile = function(path: string) end,
--[=[ --[=[
@within FS @within FS
@ -125,7 +129,7 @@ export type FS = {
@param path The directory to remove @param path The directory to remove
]=] ]=]
removeDir: (path: string) -> (), removeDir = function(path: string) end,
--[=[ --[=[
@within FS @within FS
@must_use @must_use
@ -140,7 +144,9 @@ export type FS = {
@param path The file path to check @param path The file path to check
@return If the path is a file or not @return If the path is a file or not
]=] ]=]
isFile: (path: string) -> boolean, isFile = function(path: string): boolean
return nil :: any
end,
--[=[ --[=[
@within FS @within FS
@must_use @must_use
@ -155,7 +161,9 @@ export type FS = {
@param path The directory path to check @param path The directory path to check
@return If the path is a directory or not @return If the path is a directory or not
]=] ]=]
isDir: (path: string) -> boolean, isDir = function(path: string): boolean
return nil :: any
end,
--[=[ --[=[
@within FS @within FS
@ -175,5 +183,5 @@ export type FS = {
@param to The path to move to @param to The path to move to
@param overwriteOrOptions Options for the target path, such as if should be overwritten if it already exists @param overwriteOrOptions Options for the target path, such as if should be overwritten if it already exists
]=] ]=]
move: (from: string, to: string, overwriteOrOptions: (boolean | WriteOptions)?) -> (), move = function(from: string, to: string, overwriteOrOptions: (boolean | WriteOptions)?) end,
} }

View file

@ -180,7 +180,7 @@ export type WebSocket = {
end) end)
``` ```
]=] ]=]
export type Net = { return {
--[=[ --[=[
@within Net @within Net
@ -191,7 +191,9 @@ export type Net = {
@param config The URL or request config to use @param config The URL or request config to use
@return A dictionary representing the response for the request @return A dictionary representing the response for the request
]=] ]=]
request: (config: string | FetchParams) -> FetchResponse, request = function(config: string | FetchParams): FetchResponse
return nil :: any
end,
--[=[ --[=[
@within Net @within Net
@must_use @must_use
@ -204,7 +206,9 @@ export type Net = {
@param url The URL to connect to @param url The URL to connect to
@return A web socket handle @return A web socket handle
]=] ]=]
socket: (url: string) -> WebSocket, socket = function(url: string): WebSocket
return nil :: any
end,
--[=[ --[=[
@within Net @within Net
@ -216,7 +220,9 @@ export type Net = {
@param port The port to use for the server @param port The port to use for the server
@param handlerOrConfig The handler function or config to use for the server @param handlerOrConfig The handler function or config to use for the server
]=] ]=]
serve: (port: number, handlerOrConfig: ServeHttpHandler | ServeConfig) -> ServeHandle, serve = function(port: number, handlerOrConfig: ServeHttpHandler | ServeConfig): ServeHandle
return nil :: any
end,
--[=[ --[=[
@within Net @within Net
@must_use @must_use
@ -227,7 +233,9 @@ export type Net = {
@param pretty If the encoded JSON string should include newlines and spaces. Defaults to false @param pretty If the encoded JSON string should include newlines and spaces. Defaults to false
@return The encoded JSON string @return The encoded JSON string
]=] ]=]
jsonEncode: (value: any, pretty: boolean?) -> string, jsonEncode = function(value: any, pretty: boolean?): string
return nil :: any
end,
--[=[ --[=[
@within Net @within Net
@must_use @must_use
@ -237,7 +245,9 @@ export type Net = {
@param encoded The JSON string to decode @param encoded The JSON string to decode
@return The decoded lua value @return The decoded lua value
]=] ]=]
jsonDecode: (encoded: string) -> any, jsonDecode = function(encoded: string): any
return nil :: any
end,
--[=[ --[=[
@within Net @within Net
@must_use @must_use
@ -248,7 +258,9 @@ export type Net = {
@param binary If the string should be treated as binary data and/or is not valid utf-8. Defaults to false @param binary If the string should be treated as binary data and/or is not valid utf-8. Defaults to false
@return The encoded string @return The encoded string
]=] ]=]
urlEncode: (s: string, binary: boolean?) -> string, urlEncode = function(s: string, binary: boolean?): string
return nil :: any
end,
--[=[ --[=[
@within Net @within Net
@must_use @must_use
@ -259,5 +271,7 @@ export type Net = {
@param binary If the string should be treated as binary data and/or is not valid utf-8. Defaults to false @param binary If the string should be treated as binary data and/or is not valid utf-8. Defaults to false
@return The decoded string @return The decoded string
]=] ]=]
urlDecode: (s: string, binary: boolean?) -> string, urlDecode = function(s: string, binary: boolean?): string
return nil :: any
end,
} }

View file

@ -78,7 +78,7 @@ export type SpawnResult = {
end end
``` ```
]=] ]=]
export type Process = { return {
--[=[ --[=[
@within Process @within Process
@read_only @read_only
@ -91,7 +91,7 @@ export type Process = {
* `"macos"` * `"macos"`
* `"windows"` * `"windows"`
]=] ]=]
os: OS, os = (nil :: any) :: OS,
--[=[ --[=[
@within Process @within Process
@read_only @read_only
@ -103,21 +103,21 @@ export type Process = {
* `"x86_64"` * `"x86_64"`
* `"aarch64"` * `"aarch64"`
]=] ]=]
arch: Arch, arch = (nil :: any) :: Arch,
--[=[ --[=[
@within Process @within Process
@read_only @read_only
The arguments given when running the Lune script. The arguments given when running the Lune script.
]=] ]=]
args: { string }, args = (nil :: any) :: { string },
--[=[ --[=[
@within Process @within Process
@read_only @read_only
The current working directory in which the Lune script is running. The current working directory in which the Lune script is running.
]=] ]=]
cwd: string, cwd = (nil :: any) :: string,
--[=[ --[=[
@within Process @within Process
@read_write @read_write
@ -126,7 +126,7 @@ export type Process = {
Setting a value on this table will set the corresponding environment variable. Setting a value on this table will set the corresponding environment variable.
]=] ]=]
env: { [string]: string? }, env = (nil :: any) :: { [string]: string? },
--[=[ --[=[
@within Process @within Process
@ -138,7 +138,7 @@ export type Process = {
@param code The exit code to set @param code The exit code to set
]=] ]=]
exit: (code: number?) -> (), exit = function(code: number?) end,
--[=[ --[=[
@within Process @within Process
@ -154,5 +154,7 @@ export type Process = {
@param options A dictionary of options for the child process @param options A dictionary of options for the child process
@return A dictionary representing the result of the child process @return A dictionary representing the result of the child process
]=] ]=]
spawn: (program: string, params: { string }?, options: SpawnOptions?) -> SpawnResult, spawn = function(program: string, params: { string }?, options: SpawnOptions?): SpawnResult
return nil :: any
end,
} }

View file

@ -21,7 +21,7 @@ export type Instance = {}
roblox.writePlaceFile("myPlaceFile.rbxl", game) roblox.writePlaceFile("myPlaceFile.rbxl", game)
``` ```
]=] ]=]
export type Roblox = { return {
--[=[ --[=[
@within Roblox @within Roblox
@must_use @must_use
@ -37,7 +37,9 @@ export type Roblox = {
@param filePath The file path to read from @param filePath The file path to read from
]=] ]=]
readPlaceFile: (filePath: string) -> Instance, readPlaceFile = function(filePath: string): Instance
return nil :: any
end,
--[=[ --[=[
@within Roblox @within Roblox
@must_use @must_use
@ -53,7 +55,9 @@ export type Roblox = {
@param filePath The file path to read from @param filePath The file path to read from
]=] ]=]
readModelFile: (filePath: string) -> { Instance }, readModelFile = function(filePath: string): { Instance }
return nil :: any
end,
--[=[ --[=[
@within Roblox @within Roblox
@ -69,7 +73,7 @@ export type Roblox = {
@param filePath The file path to write to @param filePath The file path to write to
@param dataModel The DataModel to write to the file @param dataModel The DataModel to write to the file
]=] ]=]
writePlaceFile: (filePath: string, dataModel: Instance) -> (), writePlaceFile = function(filePath: string, dataModel: Instance) end,
--[=[ --[=[
@within Roblox @within Roblox
@ -85,7 +89,7 @@ export type Roblox = {
@param filePath The file path to write to @param filePath The file path to write to
@param instances The array of instances to write to the file @param instances The array of instances to write to the file
]=] ]=]
writeModelFile: (filePath: string, instances: { Instance }) -> (), writeModelFile = function(filePath: string, instances: { Instance }) end,
--[=[ --[=[
@within Roblox @within Roblox
@must_use @must_use
@ -122,5 +126,7 @@ export type Roblox = {
@param raw If the cookie should be returned as a pure value or not. Defaults to false @param raw If the cookie should be returned as a pure value or not. Defaults to false
]=] ]=]
getAuthCookie: (raw: boolean?) -> string?, getAuthCookie = function(raw: boolean?): string?
return nil :: any
end,
} }

View file

@ -22,7 +22,7 @@ export type EncodeDecodeFormat = "json" | "yaml" | "toml"
fs.writeFile("myFile.yaml", serde.encode("yaml", someYaml)) fs.writeFile("myFile.yaml", serde.encode("yaml", someYaml))
``` ```
]=] ]=]
export type Serde = { return {
--[=[ --[=[
@within Serde @within Serde
@must_use @must_use
@ -34,7 +34,9 @@ export type Serde = {
@param pretty If the encoded string should be human-readable, including things such as newlines and spaces. Only supported for json and toml formats, and defaults to false @param pretty If the encoded string should be human-readable, including things such as newlines and spaces. Only supported for json and toml formats, and defaults to false
@return The encoded string @return The encoded string
]=] ]=]
encode: (format: EncodeDecodeFormat, value: any, pretty: boolean?) -> string, encode = function(format: EncodeDecodeFormat, value: any, pretty: boolean?): string
return nil :: any
end,
--[=[ --[=[
@within Serde @within Serde
@must_use @must_use
@ -45,5 +47,7 @@ export type Serde = {
@param encoded The string to decode @param encoded The string to decode
@return The decoded lua value @return The decoded lua value
]=] ]=]
decode: (format: EncodeDecodeFormat, encoded: string) -> any, decode = function(format: EncodeDecodeFormat, encoded: string): any
return nil :: any
end,
} }

View file

@ -10,6 +10,34 @@ export type Color =
| "white" | "white"
export type Style = "reset" | "bold" | "dim" export type Style = "reset" | "bold" | "dim"
type PromptFn = (
(() -> string)
& ((kind: "text", message: string?, defaultOrOptions: string?) -> string)
& ((kind: "confirm", message: string, defaultOrOptions: boolean?) -> boolean)
& ((kind: "select", message: string?, defaultOrOptions: { string }) -> number?)
& ((kind: "multiselect", message: string?, defaultOrOptions: { string }) -> { number }?)
)
--[=[
@within Stdio
@must_use
Prompts for user input using the wanted kind of prompt:
* `"text"` - Prompts for a plain text string from the user
* `"confirm"` - Prompts the user to confirm with y / n (yes / no)
* `"select"` - Prompts the user to select *one* value from a list
* `"multiselect"` - Prompts the user to select *one or more* values from a list
* `nil` - Equivalent to `"text"` with no extra arguments
@param kind The kind of prompt to use
@param message The message to show the user
@param defaultOrOptions The default value for the prompt, or options to choose from for selection prompts
]=]
local prompt: PromptFn = function(kind: any, message: any, defaultOrOptions: any)
return nil :: any
end
--[=[ --[=[
@class Stdio @class Stdio
@ -31,7 +59,7 @@ export type Style = "reset" | "bold" | "dim"
stdio.ewrite("\nAnd some error text, too") stdio.ewrite("\nAnd some error text, too")
``` ```
]=] ]=]
export type Stdio = { return {
--[=[ --[=[
@within Stdio @within Stdio
@must_use @must_use
@ -52,7 +80,9 @@ export type Stdio = {
@param color The color to use @param color The color to use
@return A printable ANSI string @return A printable ANSI string
]=] ]=]
color: (color: Color) -> string, color = function(color: Color): string
return nil :: any
end,
--[=[ --[=[
@within Stdio @within Stdio
@must_use @must_use
@ -73,7 +103,9 @@ export type Stdio = {
@param style The style to use @param style The style to use
@return A printable ANSI string @return A printable ANSI string
]=] ]=]
style: (style: Style) -> string, style = function(style: Style): string
return nil :: any
end,
--[=[ --[=[
@within Stdio @within Stdio
@must_use @must_use
@ -83,7 +115,9 @@ export type Stdio = {
@param ... The values to format @param ... The values to format
@return The formatted string @return The formatted string
]=] ]=]
format: (...any) -> string, format = function(...: any): string
return nil :: any
end,
--[=[ --[=[
@within Stdio @within Stdio
@ -91,7 +125,7 @@ export type Stdio = {
@param s The string to write to stdout @param s The string to write to stdout
]=] ]=]
write: (s: string) -> (), write = function(s: string) end,
--[=[ --[=[
@within Stdio @within Stdio
@ -99,28 +133,6 @@ export type Stdio = {
@param s The string to write to stderr @param s The string to write to stderr
]=] ]=]
ewrite: (s: string) -> (), ewrite = function(s: string) end,
--[=[ prompt = prompt,
@within Stdio
@must_use
Prompts for user input using the wanted kind of prompt:
* `"text"` - Prompts for a plain text string from the user
* `"confirm"` - Prompts the user to confirm with y / n (yes / no)
* `"select"` - Prompts the user to select *one* value from a list
* `"multiselect"` - Prompts the user to select *one or more* values from a list
* `nil` - Equivalent to `"text"` with no extra arguments
@param kind The kind of prompt to use
@param message The message to show the user
@param defaultOrOptions The default value for the prompt, or options to choose from for selection prompts
]=]
prompt: (
(() -> string)
& ((kind: "text", message: string?, defaultOrOptions: string?) -> string)
& ((kind: "confirm", message: string, defaultOrOptions: boolean?) -> boolean)
& ((kind: "select", message: string?, defaultOrOptions: { string }) -> number?)
& ((kind: "multiselect", message: string?, defaultOrOptions: { string }) -> { number }?)
),
} }

View file

@ -27,7 +27,7 @@
print("Running after task.spawn yields") print("Running after task.spawn yields")
``` ```
]=] ]=]
export type Task = { return {
--[=[ --[=[
@within Task @within Task
@ -35,7 +35,7 @@ export type Task = {
@param thread The thread to cancel @param thread The thread to cancel
]=] ]=]
cancel: (thread: thread) -> (), cancel = function(thread: thread) end,
--[=[ --[=[
@within Task @within Task
@ -44,16 +44,26 @@ export type Task = {
@param functionOrThread The function or thread to defer @param functionOrThread The function or thread to defer
@return The thread that will be deferred @return The thread that will be deferred
]=] ]=]
defer: <T...>(functionOrThread: thread | (T...) -> ...any, T...) -> thread, defer = function<T...>(functionOrThread: thread | (T...) -> ...any, ...: T...): thread
return nil :: any
end,
--[=[ --[=[
@within Task @within Task
Delays a thread or function to run after `duration` seconds. Delays a thread or function to run after `duration` seconds.
If no `duration` is given, this will wait for the minimum amount of time possible.
@param functionOrThread The function or thread to delay @param functionOrThread The function or thread to delay
@return The thread that will be delayed @return The thread that will be delayed
]=] ]=]
delay: <T...>(duration: number?, functionOrThread: thread | (T...) -> ...any, T...) -> thread, delay = function<T...>(
duration: number?,
functionOrThread: thread | (T...) -> ...any,
...: T...
): thread
return nil :: any
end,
--[=[ --[=[
@within Task @within Task
@ -65,7 +75,9 @@ export type Task = {
@param functionOrThread The function or thread to spawn @param functionOrThread The function or thread to spawn
@return The thread that was spawned @return The thread that was spawned
]=] ]=]
spawn: <T...>(functionOrThread: thread | (T...) -> ...any, T...) -> thread, spawn = function<T...>(functionOrThread: thread | (T...) -> ...any, ...: T...): thread
return nil :: any
end,
--[=[ --[=[
@within Task @within Task
@ -77,5 +89,7 @@ export type Task = {
@param duration The amount of time to wait @param duration The amount of time to wait
@return The exact amount of time waited @return The exact amount of time waited
]=] ]=]
wait: (duration: number?) -> number, wait = function(duration: number?): number
return nil :: any
end,
} }

View file

@ -18,8 +18,24 @@ pub async fn generate_gitbook_dir_from_definitions(dir: &Dir<'_>) -> Result<()>
pub async fn generate_typedef_files_from_definitions( pub async fn generate_typedef_files_from_definitions(
dir: &Dir<'_>, dir: &Dir<'_>,
) -> Result<HashMap<String, PathBuf>> { ) -> Result<HashMap<String, PathBuf>> {
let definitions = read_typedefs_dir(dir)?; let contents = read_typedefs_dir_contents(dir);
typedef_files::generate_from_type_definitions(definitions).await typedef_files::generate_from_type_definitions(contents).await
}
fn read_typedefs_dir_contents(dir: &Dir<'_>) -> HashMap<String, Vec<u8>> {
let mut definitions = HashMap::new();
for entry in dir.find("*.luau").unwrap() {
let entry_file = entry.as_file().unwrap();
let entry_name = entry_file.path().file_name().unwrap().to_string_lossy();
let typedef_name = entry_name.trim_end_matches(".luau");
let typedef_contents = entry_file.contents().to_vec();
definitions.insert(typedef_name.to_string(), typedef_contents);
}
definitions
} }
fn read_typedefs_dir(dir: &Dir<'_>) -> Result<HashMap<String, DefinitionsTree>> { fn read_typedefs_dir(dir: &Dir<'_>) -> Result<HashMap<String, DefinitionsTree>> {

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, fmt::Write, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use directories::UserDirs; use directories::UserDirs;
@ -6,13 +6,9 @@ use directories::UserDirs;
use futures_util::future::try_join_all; use futures_util::future::try_join_all;
use tokio::fs::{create_dir_all, write}; use tokio::fs::{create_dir_all, write};
use super::definitions::{DefinitionsItem, DefinitionsTree};
const GENERATED_COMMENT_TAG: &str = "--!strict";
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub async fn generate_from_type_definitions( pub async fn generate_from_type_definitions(
api_reference: HashMap<String, DefinitionsTree>, typedef_files: HashMap<String, Vec<u8>>,
) -> Result<HashMap<String, PathBuf>> { ) -> Result<HashMap<String, PathBuf>> {
let mut dirs_to_write = Vec::new(); let mut dirs_to_write = Vec::new();
let mut files_to_write = Vec::new(); let mut files_to_write = Vec::new();
@ -25,19 +21,11 @@ pub async fn generate_from_type_definitions(
.join(env!("CARGO_PKG_VERSION")); .join(env!("CARGO_PKG_VERSION"));
dirs_to_write.push(cache_dir.clone()); dirs_to_write.push(cache_dir.clone());
// Make typedef files // Make typedef files
for (category_name, category_tree) in api_reference { for (builtin_name, builtin_typedef) in typedef_files {
let path = cache_dir let path = cache_dir
.join(category_name.to_ascii_lowercase()) .join(builtin_name.to_ascii_lowercase())
.with_extension("luau"); .with_extension("luau");
let mut contents = String::new(); files_to_write.push((builtin_name.to_lowercase(), path, builtin_typedef));
write!(
contents,
"{GENERATED_COMMENT_TAG}\n-- @lune/{} {}\n",
category_name.to_lowercase(),
env!("CARGO_PKG_VERSION")
)?;
write_tree(&mut contents, category_name.to_string(), category_tree)?;
files_to_write.push((category_name.to_lowercase(), path, contents));
} }
// Write all dirs and files only when we know generation was successful // Write all dirs and files only when we know generation was successful
let futs_dirs = dirs_to_write let futs_dirs = dirs_to_write
@ -55,113 +43,3 @@ pub async fn generate_from_type_definitions(
.map(|(name, path, _)| (name, path)) .map(|(name, path, _)| (name, path))
.collect::<HashMap<_, _>>()) .collect::<HashMap<_, _>>())
} }
fn make_return_table_item(item: &DefinitionsItem) -> Result<String> {
let mut description = String::new();
if let Some(desc) = item.children().iter().find(|child| child.is_description()) {
write!(description, "\n{}\n", desc.get_value().unwrap().trim())?;
for tag in item.children().iter().filter(|child| child.is_tag()) {
let tag_name = tag.get_name().unwrap();
if tag_name == "param" {
write!(
description,
"\n@param {} {}",
tag.get_meta().unwrap(),
tag.get_value().unwrap()
)?;
} else if tag_name == "return" {
write!(description, "\n@return {}", tag.get_value().unwrap())?;
}
}
}
let mut contents = String::new();
if item.is_function() {
let args = item
.args()
.iter()
.map(|arg| format!("{}: {}", arg.name.trim(), arg.typedef.trim()))
.collect::<Vec<_>>()
.join(", ");
// HACK: We should probably handle vararg and generics properly but this works for now...
let args = args
.replace("_: ...any", "...: any")
.replace("_: T...", "...: any")
.replace("(T...)", "(...any)");
write!(contents, "function({args})")?;
write!(contents, "\n\treturn nil :: any")?;
write!(contents, "\nend,")?;
} else if item.is_property() {
write!(contents, "(nil :: any) :: {},", item.get_type().unwrap())?;
}
Ok(format!(
"\n--[=[{}\n]=]\n{} = {}",
description.trim_end().replace('\n', "\n\t"),
item.get_name().unwrap_or("_"),
contents
))
}
fn write_tree(contents: &mut String, name: String, root: DefinitionsTree) -> Result<()> {
let main = root
.children()
.iter()
.find(|c| matches!(c.get_name(), Some(s) if s.to_lowercase() == name.to_lowercase()))
.expect("Failed to find main export for generating typedef file");
let mut description = String::new();
if let Some(desc) = main.children().iter().find(|child| child.is_description()) {
write!(description, "\n{}\n", desc.get_value().unwrap().trim())?;
}
let children = root
.children()
.iter()
.filter(|child| child != &main)
.collect::<Vec<_>>();
for child in children {
if child.is_type() || child.is_table() || child.is_function() || child.is_property() {
let mut child_description = String::new();
if let Some(desc) = child.children().iter().find(|child| child.is_description()) {
write!(
child_description,
"\n{}\n",
desc.get_value().unwrap().trim()
)?;
write!(
contents,
"\n--[=[{}\n]=]",
child_description.trim_end().replace('\n', "\n\t"),
)?;
}
if child.is_exported() {
write!(contents, "\nexport ")?;
}
writeln!(
contents,
"type {} = {}",
child.get_name().unwrap(),
child.get_type().unwrap()
)?;
}
}
let mut ret_table = String::new();
for child in main
.children()
.iter()
.filter(|child| child.is_function() || child.is_property())
{
write!(ret_table, "{}", make_return_table_item(child)?)?;
}
write!(
contents,
"\n--[=[{}\n]=]\nreturn {{\n{}\n}}\n",
description.trim_end().replace('\n', "\n\t"),
ret_table.trim_end().replace('\n', "\n\t")
)?;
Ok(())
}