mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Added global types to documentation site
This commit is contained in:
parent
1559e69de6
commit
d4d9108947
9 changed files with 204 additions and 60 deletions
|
@ -8,6 +8,12 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Added global types to documentation site
|
||||||
|
|
||||||
## `0.6.6` - April 30th, 2023
|
## `0.6.6` - April 30th, 2023
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -123,6 +123,9 @@ impl Cli {
|
||||||
|| self.generate_docs_file
|
|| self.generate_docs_file
|
||||||
|| self.generate_gitbook_dir;
|
|| self.generate_gitbook_dir;
|
||||||
if generate_file_requested {
|
if generate_file_requested {
|
||||||
|
if self.generate_gitbook_dir {
|
||||||
|
generate_gitbook_dir_from_definitions(&TYPEDEFS_DIR).await?;
|
||||||
|
}
|
||||||
let definitions = generate_typedefs_file_from_dir(&TYPEDEFS_DIR);
|
let definitions = generate_typedefs_file_from_dir(&TYPEDEFS_DIR);
|
||||||
if self.generate_luau_types {
|
if self.generate_luau_types {
|
||||||
generate_and_save_file(FILE_NAME_LUAU_TYPES, "Luau type definitions", || {
|
generate_and_save_file(FILE_NAME_LUAU_TYPES, "Luau type definitions", || {
|
||||||
|
@ -142,9 +145,6 @@ impl Cli {
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
if self.generate_gitbook_dir {
|
|
||||||
generate_gitbook_dir_from_definitions(&definitions).await?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if self.script_path.is_none() {
|
if self.script_path.is_none() {
|
||||||
// Only generating typedefs without running a script is completely
|
// Only generating typedefs without running a script is completely
|
||||||
|
|
|
@ -9,6 +9,7 @@ use super::{
|
||||||
pub struct DefinitionsItemBuilder {
|
pub struct DefinitionsItemBuilder {
|
||||||
exported: bool,
|
exported: bool,
|
||||||
kind: Option<DefinitionsItemKind>,
|
kind: Option<DefinitionsItemKind>,
|
||||||
|
typ: Option<String>,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
meta: Option<String>,
|
meta: Option<String>,
|
||||||
value: Option<String>,
|
value: Option<String>,
|
||||||
|
@ -41,6 +42,11 @@ impl DefinitionsItemBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_type(mut self, typ: String) -> Self {
|
||||||
|
self.typ = Some(typ);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_meta<S: AsRef<str>>(mut self, meta: S) -> Self {
|
pub fn with_meta<S: AsRef<str>>(mut self, meta: S) -> Self {
|
||||||
self.meta = Some(meta.as_ref().to_string());
|
self.meta = Some(meta.as_ref().to_string());
|
||||||
self
|
self
|
||||||
|
@ -88,10 +94,11 @@ impl DefinitionsItemBuilder {
|
||||||
pub fn build(self) -> Result<DefinitionsItem> {
|
pub fn build(self) -> Result<DefinitionsItem> {
|
||||||
if let Some(kind) = self.kind {
|
if let Some(kind) = self.kind {
|
||||||
let mut children = self.children;
|
let mut children = self.children;
|
||||||
children.sort();
|
children.sort_by(|left, right| left.name.cmp(&right.name));
|
||||||
Ok(DefinitionsItem {
|
Ok(DefinitionsItem {
|
||||||
exported: self.exported,
|
exported: self.exported,
|
||||||
kind,
|
kind,
|
||||||
|
typ: self.typ,
|
||||||
name: self.name,
|
name: self.name,
|
||||||
meta: self.meta,
|
meta: self.meta,
|
||||||
value: self.value,
|
value: self.value,
|
||||||
|
@ -104,3 +111,19 @@ impl DefinitionsItemBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&DefinitionsItem> for DefinitionsItemBuilder {
|
||||||
|
fn from(value: &DefinitionsItem) -> Self {
|
||||||
|
Self {
|
||||||
|
exported: value.exported,
|
||||||
|
kind: Some(value.kind),
|
||||||
|
typ: value.typ.clone(),
|
||||||
|
name: value.name.clone(),
|
||||||
|
meta: value.meta.clone(),
|
||||||
|
value: value.value.clone(),
|
||||||
|
children: value.children.clone(),
|
||||||
|
args: value.args.clone(),
|
||||||
|
rets: value.rets.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -45,12 +45,13 @@ impl DefinitionsItemFunctionRet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DefinitionsItem {
|
pub struct DefinitionsItem {
|
||||||
#[serde(skip_serializing_if = "skip_serialize_is_false")]
|
#[serde(skip_serializing_if = "skip_serialize_is_false")]
|
||||||
pub(super) exported: bool,
|
pub(super) exported: bool,
|
||||||
pub(super) kind: DefinitionsItemKind,
|
pub(super) kind: DefinitionsItemKind,
|
||||||
|
pub(super) typ: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub(super) name: Option<String>,
|
pub(super) name: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
@ -95,12 +96,6 @@ impl PartialOrd for DefinitionsItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for DefinitionsItem {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
self.partial_cmp(other).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl DefinitionsItem {
|
impl DefinitionsItem {
|
||||||
pub fn is_exported(&self) -> bool {
|
pub fn is_exported(&self) -> bool {
|
||||||
|
@ -111,6 +106,10 @@ impl DefinitionsItem {
|
||||||
self.kind.is_root()
|
self.kind.is_root()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_type(&self) -> bool {
|
||||||
|
self.kind.is_type()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_table(&self) -> bool {
|
pub fn is_table(&self) -> bool {
|
||||||
self.kind.is_table()
|
self.kind.is_table()
|
||||||
}
|
}
|
||||||
|
@ -139,6 +138,10 @@ impl DefinitionsItem {
|
||||||
self.name.as_deref()
|
self.name.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_type(&self) -> Option<String> {
|
||||||
|
self.typ.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_meta(&self) -> Option<&str> {
|
pub fn get_meta(&self) -> Option<&str> {
|
||||||
self.meta.as_deref()
|
self.meta.as_deref()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
pub enum DefinitionsItemKind {
|
pub enum DefinitionsItemKind {
|
||||||
Root,
|
Root,
|
||||||
|
Type,
|
||||||
Table,
|
Table,
|
||||||
Property,
|
Property,
|
||||||
Function,
|
Function,
|
||||||
|
@ -19,6 +20,10 @@ impl DefinitionsItemKind {
|
||||||
self == DefinitionsItemKind::Root
|
self == DefinitionsItemKind::Root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_type(self) -> bool {
|
||||||
|
self == DefinitionsItemKind::Type
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_table(self) -> bool {
|
pub fn is_table(self) -> bool {
|
||||||
self == DefinitionsItemKind::Table
|
self == DefinitionsItemKind::Table
|
||||||
}
|
}
|
||||||
|
@ -47,6 +52,7 @@ impl fmt::Display for DefinitionsItemKind {
|
||||||
"{}",
|
"{}",
|
||||||
match self {
|
match self {
|
||||||
Self::Root => "Root",
|
Self::Root => "Root",
|
||||||
|
Self::Type => "Type",
|
||||||
Self::Table => "Table",
|
Self::Table => "Table",
|
||||||
Self::Property => "Property",
|
Self::Property => "Property",
|
||||||
Self::Function => "Function",
|
Self::Function => "Function",
|
||||||
|
|
|
@ -12,7 +12,7 @@ use regex::Regex;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
builder::DefinitionsItemBuilder, item::DefinitionsItem, moonwave::parse_moonwave_style_comment,
|
builder::DefinitionsItemBuilder, item::DefinitionsItem, moonwave::parse_moonwave_style_comment,
|
||||||
type_info_ext::TypeInfoExt,
|
type_info_ext::TypeInfoExt, DefinitionsItemKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -26,6 +26,7 @@ struct DefinitionsParserItem {
|
||||||
pub struct DefinitionsParser {
|
pub struct DefinitionsParser {
|
||||||
found_top_level_items: BTreeMap<String, DefinitionsParserItem>,
|
found_top_level_items: BTreeMap<String, DefinitionsParserItem>,
|
||||||
found_top_level_types: HashMap<String, TypeInfo>,
|
found_top_level_types: HashMap<String, TypeInfo>,
|
||||||
|
found_top_level_comments: HashMap<String, Option<String>>,
|
||||||
found_top_level_declares: Vec<String>,
|
found_top_level_declares: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ impl DefinitionsParser {
|
||||||
Self {
|
Self {
|
||||||
found_top_level_items: BTreeMap::new(),
|
found_top_level_items: BTreeMap::new(),
|
||||||
found_top_level_types: HashMap::new(),
|
found_top_level_types: HashMap::new(),
|
||||||
|
found_top_level_comments: HashMap::new(),
|
||||||
found_top_level_declares: Vec::new(),
|
found_top_level_declares: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +71,7 @@ impl DefinitionsParser {
|
||||||
// Parse contents into top-level parser items for later use
|
// Parse contents into top-level parser items for later use
|
||||||
let mut found_top_level_items = BTreeMap::new();
|
let mut found_top_level_items = BTreeMap::new();
|
||||||
let mut found_top_level_types = HashMap::new();
|
let mut found_top_level_types = HashMap::new();
|
||||||
|
let mut found_top_level_comments = HashMap::new();
|
||||||
let ast =
|
let ast =
|
||||||
full_moon::parse(&resulting_contents).context("Failed to parse type definitions")?;
|
full_moon::parse(&resulting_contents).context("Failed to parse type definitions")?;
|
||||||
for stmt in ast.nodes().stmts() {
|
for stmt in ast.nodes().stmts() {
|
||||||
|
@ -80,28 +83,36 @@ impl DefinitionsParser {
|
||||||
_ => None,
|
_ => None,
|
||||||
} {
|
} {
|
||||||
let name = declaration.type_name().token().to_string();
|
let name = declaration.type_name().token().to_string();
|
||||||
|
let comment = find_token_moonwave_comment(token_reference);
|
||||||
found_top_level_items.insert(
|
found_top_level_items.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
DefinitionsParserItem {
|
DefinitionsParserItem {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
comment: find_token_moonwave_comment(token_reference),
|
comment: comment.clone(),
|
||||||
type_info: declaration.type_definition().clone(),
|
type_info: declaration.type_definition().clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
found_top_level_types.insert(name, declaration.type_definition().clone());
|
found_top_level_types.insert(name.clone(), declaration.type_definition().clone());
|
||||||
|
found_top_level_comments.insert(name, comment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Store results
|
// Store results
|
||||||
self.found_top_level_items = found_top_level_items;
|
self.found_top_level_items = found_top_level_items;
|
||||||
self.found_top_level_types = found_top_level_types;
|
self.found_top_level_types = found_top_level_types;
|
||||||
|
self.found_top_level_comments = found_top_level_comments;
|
||||||
self.found_top_level_declares = found_declares;
|
self.found_top_level_declares = found_declares;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_parser_item_into_doc_item(&self, item: DefinitionsParserItem) -> DefinitionsItem {
|
fn convert_parser_item_into_doc_item(
|
||||||
|
&self,
|
||||||
|
item: DefinitionsParserItem,
|
||||||
|
kind: Option<DefinitionsItemKind>,
|
||||||
|
) -> DefinitionsItem {
|
||||||
let mut builder = DefinitionsItemBuilder::new()
|
let mut builder = DefinitionsItemBuilder::new()
|
||||||
.with_kind(item.type_info.parse_definitions_kind())
|
.with_kind(kind.unwrap_or_else(|| item.type_info.parse_definitions_kind()))
|
||||||
.with_name(&item.name);
|
.with_name(&item.name)
|
||||||
|
.with_type(item.type_info.to_string());
|
||||||
if self.found_top_level_declares.contains(&item.name) {
|
if self.found_top_level_declares.contains(&item.name) {
|
||||||
builder = builder.as_exported();
|
builder = builder.as_exported();
|
||||||
}
|
}
|
||||||
|
@ -123,6 +134,7 @@ impl DefinitionsParser {
|
||||||
comment: find_token_moonwave_comment(name),
|
comment: find_token_moonwave_comment(name),
|
||||||
type_info: field.value().clone(),
|
type_info: field.value().clone(),
|
||||||
},
|
},
|
||||||
|
None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,14 +149,16 @@ impl DefinitionsParser {
|
||||||
*/
|
*/
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
pub fn drain(&mut self) -> Result<Vec<DefinitionsItem>> {
|
pub fn drain(&mut self) -> Result<Vec<DefinitionsItem>> {
|
||||||
let mut results = Vec::new();
|
let mut resulting_items = Vec::new();
|
||||||
for top_level_item in self.found_top_level_items.values() {
|
for top_level_item in self.found_top_level_items.values() {
|
||||||
results.push(self.convert_parser_item_into_doc_item(top_level_item.clone()));
|
resulting_items
|
||||||
|
.push(self.convert_parser_item_into_doc_item(top_level_item.clone(), None));
|
||||||
}
|
}
|
||||||
self.found_top_level_items = BTreeMap::new();
|
self.found_top_level_items = BTreeMap::new();
|
||||||
self.found_top_level_types = HashMap::new();
|
self.found_top_level_types = HashMap::new();
|
||||||
|
self.found_top_level_comments = HashMap::new();
|
||||||
self.found_top_level_declares = Vec::new();
|
self.found_top_level_declares = Vec::new();
|
||||||
Ok(results)
|
Ok(resulting_items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use super::{
|
||||||
parser::DefinitionsParser,
|
parser::DefinitionsParser,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct DefinitionsTree(DefinitionsItem);
|
pub struct DefinitionsTree(DefinitionsItem);
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -18,8 +18,8 @@ All globals that are not available under a specific scope.
|
||||||
These are to be used directly without indexing a global table first.
|
These are to be used directly without indexing a global table first.
|
||||||
";
|
";
|
||||||
|
|
||||||
pub async fn generate_from_type_definitions(contents: &str) -> Result<()> {
|
#[allow(clippy::too_many_lines)]
|
||||||
let tree = DefinitionsTree::from_type_definitions(contents)?;
|
pub async fn generate_from_type_definitions(contents: HashMap<String, String>) -> Result<()> {
|
||||||
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();
|
||||||
// Create the gitbook dir at the repo root
|
// Create the gitbook dir at the repo root
|
||||||
|
@ -37,22 +37,42 @@ pub async fn generate_from_type_definitions(contents: &str) -> Result<()> {
|
||||||
dirs_to_write.push(path_gitbook_api_dir.clone());
|
dirs_to_write.push(path_gitbook_api_dir.clone());
|
||||||
// Sort doc items into subcategories based on globals
|
// Sort doc items into subcategories based on globals
|
||||||
let mut api_reference = HashMap::new();
|
let mut api_reference = HashMap::new();
|
||||||
let mut no_category = Vec::new();
|
let mut without_main_item = Vec::new();
|
||||||
for top_level_item in tree
|
for (typedef_name, typedef_contents) in contents {
|
||||||
|
let tree = DefinitionsTree::from_type_definitions(typedef_contents)?;
|
||||||
|
let main = tree.children().iter().find(
|
||||||
|
|c| matches!(c.get_name(), Some(s) if s.to_lowercase() == typedef_name.to_lowercase()),
|
||||||
|
);
|
||||||
|
if let Some(main) = main {
|
||||||
|
let children = tree
|
||||||
.children()
|
.children()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|top_level| top_level.is_exported())
|
.filter_map(|child| {
|
||||||
{
|
if child == main {
|
||||||
match top_level_item.kind() {
|
None
|
||||||
DefinitionsItemKind::Table => {
|
} else {
|
||||||
let category_name =
|
Some(
|
||||||
get_name(top_level_item).context("Missing name for top-level doc item")?;
|
DefinitionsItemBuilder::from(child)
|
||||||
api_reference.insert(category_name, top_level_item.clone());
|
.with_kind(DefinitionsItemKind::Type)
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
DefinitionsItemKind::Function => {
|
})
|
||||||
no_category.push(top_level_item.clone());
|
.collect::<Vec<_>>();
|
||||||
|
let root = DefinitionsItemBuilder::new()
|
||||||
|
.with_kind(main.kind())
|
||||||
|
.with_name(main.get_name().unwrap())
|
||||||
|
.with_children(main.children())
|
||||||
|
.with_children(&children);
|
||||||
|
api_reference.insert(
|
||||||
|
typedef_name.clone(),
|
||||||
|
root.build().expect("Failed to build root definitions item"),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
for top_level_item in tree.children() {
|
||||||
|
without_main_item.push(top_level_item.clone());
|
||||||
}
|
}
|
||||||
_ => unimplemented!("Globals other than tables and functions are not yet implemented"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert globals with no category into a new "Uncategorized" global
|
// Insert globals with no category into a new "Uncategorized" global
|
||||||
|
@ -61,7 +81,7 @@ pub async fn generate_from_type_definitions(contents: &str) -> Result<()> {
|
||||||
DefinitionsItemBuilder::new()
|
DefinitionsItemBuilder::new()
|
||||||
.with_kind(DefinitionsItemKind::Table)
|
.with_kind(DefinitionsItemKind::Table)
|
||||||
.with_name("Uncategorized")
|
.with_name("Uncategorized")
|
||||||
.with_children(&no_category)
|
.with_children(&without_main_item)
|
||||||
.with_child(
|
.with_child(
|
||||||
DefinitionsItemBuilder::new()
|
DefinitionsItemBuilder::new()
|
||||||
.with_kind(DefinitionsItemKind::Description)
|
.with_kind(DefinitionsItemKind::Description)
|
||||||
|
@ -78,7 +98,7 @@ pub async fn generate_from_type_definitions(contents: &str) -> Result<()> {
|
||||||
.with_extension("md");
|
.with_extension("md");
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
write!(contents, "{GENERATED_COMMENT_TAG}\n\n")?;
|
write!(contents, "{GENERATED_COMMENT_TAG}\n\n")?;
|
||||||
generate_markdown_documentation(&mut contents, &category_item, 0)?;
|
generate_markdown_documentation(&mut contents, &category_item, None, 0)?;
|
||||||
files_to_write.push((path, post_process_docs(contents)));
|
files_to_write.push((path, post_process_docs(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
|
||||||
|
@ -113,13 +133,16 @@ fn get_name(item: &DefinitionsItem) -> Result<String> {
|
||||||
.context("Definitions item is missing a name")
|
.context("Definitions item is missing a name")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
fn generate_markdown_documentation(
|
fn generate_markdown_documentation(
|
||||||
contents: &mut String,
|
contents: &mut String,
|
||||||
item: &DefinitionsItem,
|
item: &DefinitionsItem,
|
||||||
|
parent: Option<&DefinitionsItem>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match item.kind() {
|
match item.kind() {
|
||||||
DefinitionsItemKind::Table
|
DefinitionsItemKind::Type
|
||||||
|
| DefinitionsItemKind::Table
|
||||||
| DefinitionsItemKind::Property
|
| DefinitionsItemKind::Property
|
||||||
| DefinitionsItemKind::Function => {
|
| DefinitionsItemKind::Function => {
|
||||||
write!(
|
write!(
|
||||||
|
@ -146,17 +169,31 @@ fn generate_markdown_documentation(
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if item.kind().is_function() && !item.args().is_empty() {
|
if item.is_function() && !item.args().is_empty() {
|
||||||
let args = item
|
let args = item
|
||||||
.args()
|
.args()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| format!("{}: {}", arg.name, arg.typedef))
|
.map(|arg| format!("{}: {}", arg.name.trim(), arg.typedef.trim()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
.replace("_: T...", "T...");
|
||||||
|
let func_name = item.get_name().unwrap_or("_");
|
||||||
|
let parent_name = parent.unwrap().get_name().unwrap_or("_");
|
||||||
|
let parent_pre = if parent_name.to_lowercase() == "uncategorized" {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
format!("{parent_name}.")
|
||||||
|
};
|
||||||
write!(
|
write!(
|
||||||
contents,
|
contents,
|
||||||
"\n```lua\nfunction {}({})\n```\n",
|
"\n```lua\nfunction {parent_pre}{func_name}({args})\n```\n",
|
||||||
|
)?;
|
||||||
|
} else if item.is_type() {
|
||||||
|
write!(
|
||||||
|
contents,
|
||||||
|
"\n```lua\ntype {} = {}\n```\n",
|
||||||
item.get_name().unwrap_or("_"),
|
item.get_name().unwrap_or("_"),
|
||||||
args.join(", ")
|
item.get_type().unwrap_or_else(|| "{}".to_string()).trim()
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
let descriptions = item
|
let descriptions = item
|
||||||
|
@ -174,24 +211,50 @@ fn generate_markdown_documentation(
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|child| child.is_function())
|
.filter(|child| child.is_function())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
let types = item
|
||||||
|
.children()
|
||||||
|
.iter()
|
||||||
|
.filter(|child| child.is_type())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
for description in descriptions {
|
for description in descriptions {
|
||||||
generate_markdown_documentation(contents, description, depth + 1)?;
|
generate_markdown_documentation(contents, description, Some(item), depth + 1)?;
|
||||||
}
|
}
|
||||||
|
if !item.is_type() {
|
||||||
if !properties.is_empty() {
|
if !properties.is_empty() {
|
||||||
write!(contents, "\n\n---\n\n## Properties\n\n")?;
|
write!(contents, "\n\n---\n\n## Properties\n\n")?;
|
||||||
}
|
}
|
||||||
for property in properties {
|
for property in properties {
|
||||||
generate_markdown_documentation(contents, property, depth + 1)?;
|
generate_markdown_documentation(contents, property, Some(item), depth + 1)?;
|
||||||
}
|
}
|
||||||
if !functions.is_empty() {
|
if !functions.is_empty() {
|
||||||
write!(contents, "\n\n---\n\n## Functions\n\n")?;
|
write!(contents, "\n\n---\n\n## Functions\n\n")?;
|
||||||
}
|
}
|
||||||
for function in functions {
|
for function in functions {
|
||||||
generate_markdown_documentation(contents, function, depth + 1)?;
|
generate_markdown_documentation(contents, function, Some(item), depth + 1)?;
|
||||||
|
}
|
||||||
|
if !types.is_empty() {
|
||||||
|
write!(contents, "\n\n---\n\n## Types\n\n")?;
|
||||||
|
}
|
||||||
|
for typ in types {
|
||||||
|
generate_markdown_documentation(contents, typ, Some(item), depth + 1)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_process_docs(contents: String) -> String {
|
fn post_process_docs(contents: String) -> String {
|
||||||
contents.replace("\n\n\n", "\n\n")
|
let no_empty_lines = contents
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
if line.chars().all(char::is_whitespace) {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
line
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
no_empty_lines
|
||||||
|
.replace("\n\n\n", "\n\n")
|
||||||
|
.replace("\n\n\n", "\n\n")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use include_dir::Dir;
|
use include_dir::Dir;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
|
@ -9,10 +12,36 @@ mod selene_defs;
|
||||||
pub mod definitions;
|
pub mod definitions;
|
||||||
|
|
||||||
pub use docs_file::generate_from_type_definitions as generate_docs_json_from_definitions;
|
pub use docs_file::generate_from_type_definitions as generate_docs_json_from_definitions;
|
||||||
pub use gitbook_dir::generate_from_type_definitions as generate_gitbook_dir_from_definitions;
|
|
||||||
pub use luau_defs::generate_from_type_definitions as generate_luau_defs_from_definitions;
|
pub use luau_defs::generate_from_type_definitions as generate_luau_defs_from_definitions;
|
||||||
pub use selene_defs::generate_from_type_definitions as generate_selene_defs_from_definitions;
|
pub use selene_defs::generate_from_type_definitions as generate_selene_defs_from_definitions;
|
||||||
|
|
||||||
|
pub async fn generate_gitbook_dir_from_definitions(dir: &Dir<'_>) -> Result<()> {
|
||||||
|
let mut result = 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_utf8()
|
||||||
|
.unwrap()
|
||||||
|
.to_string()
|
||||||
|
.replace(
|
||||||
|
&format!("export type {typedef_name} = "),
|
||||||
|
&format!("declare {}: ", typedef_name.to_ascii_lowercase()),
|
||||||
|
)
|
||||||
|
.replace("export type ", "type ");
|
||||||
|
|
||||||
|
result.insert(typedef_name.to_string(), typedef_contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
match gitbook_dir::generate_from_type_definitions(result).await {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_typedefs_file_from_dir(dir: &Dir<'_>) -> String {
|
pub fn generate_typedefs_file_from_dir(dir: &Dir<'_>) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue