Preserve order for json ser/de

This commit is contained in:
Filip Tibell 2023-02-16 12:05:54 +01:00
parent 2716e4f72a
commit 1bee0986c7
No known key found for this signature in database
7 changed files with 519 additions and 514 deletions

1
Cargo.lock generated
View file

@ -1273,6 +1273,7 @@ version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [ dependencies = [
"indexmap",
"itoa", "itoa",
"ryu", "ryu",
"serde", "serde",

View file

@ -23,9 +23,9 @@ panic = "abort" # Remove extra panic info
console = "0.15.5" console = "0.15.5"
lazy_static = "1.4.0" lazy_static = "1.4.0"
serde_json = "1.0.91"
serde = { version = "1.0.152", features = ["derive"] } serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.91", features = ["preserve_order"] }
tokio = { version = "1.24.2", features = ["full"] } tokio = { version = "1.24.2", features = ["full"] }
[workspace.dependencies.reqwest] [workspace.dependencies.reqwest]

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,12 @@ use std::collections::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
mod tag;
mod visitor;
pub use tag::*;
pub use visitor::*;
#[derive(Serialize, Deserialize, Default, Debug, Clone)] #[derive(Serialize, Deserialize, Default, Debug, Clone)]
pub struct DocsGlobal { pub struct DocsGlobal {
pub documentation: String, pub documentation: String,

View file

@ -1,13 +1,15 @@
use anyhow::Result;
use full_moon::{ use full_moon::{
ast::types::{ExportedTypeDeclaration, TypeField, TypeFieldKey}, ast::types::{ExportedTypeDeclaration, TypeField, TypeFieldKey},
parse as parse_luau_ast,
tokenizer::{Token, TokenType}, tokenizer::{Token, TokenType},
visitors::Visitor, visitors::Visitor,
}; };
use regex::Regex; use regex::Regex;
use super::{ use super::{
doc::{DocsFunction, DocsFunctionParamLink, DocsGlobal, DocsParam, DocsReturn}, {DocsFunction, DocsFunctionParamLink, DocsGlobal, DocsParam, DocsReturn},
tag::{DocsTag, DocsTagKind, DocsTagList}, {DocsTag, DocsTagKind, DocsTagList},
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -31,6 +33,25 @@ impl DocumentationVisitor {
} }
} }
pub fn from_definitions(definitions_file_contents: &str) -> Result<Self> {
// TODO: Properly handle the "declare class" syntax, for now we just skip it
let mut no_declares = definitions_file_contents.to_string();
while let Some(dec) = no_declares.find("\ndeclare class") {
let end = no_declares.find("\nend").unwrap();
let before = &no_declares[0..dec];
let after = &no_declares[end + 4..];
no_declares = format!("{before}{after}");
}
let (regex, replacement) = (
Regex::new(r#"declare (?P<n>\w+): "#).unwrap(),
r#"export type $n = "#,
);
let defs_ast = parse_luau_ast(&regex.replace_all(&no_declares, replacement))?;
let mut visitor = DocumentationVisitor::new();
visitor.visit_ast(&defs_ast);
Ok(visitor)
}
pub fn parse_moonwave_style_tag(&self, line: &str) -> Option<DocsTag> { pub fn parse_moonwave_style_tag(&self, line: &str) -> Option<DocsTag> {
if self.tag_regex.is_match(line) { if self.tag_regex.is_match(line) {
let captures = self.tag_regex.captures(line).unwrap(); let captures = self.tag_regex.captures(line).unwrap();

View file

@ -1,47 +1,24 @@
use std::{collections::HashMap, fmt::Write, path::PathBuf}; use std::{collections::HashMap, fmt::Write, path::PathBuf};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use regex::Regex; use serde_json::{Map as JsonMap, Value as JsonValue};
use serde_json::{Map, Value};
use full_moon::{parse as parse_luau_ast, visitors::Visitor};
use tokio::fs::{create_dir_all, write}; use tokio::fs::{create_dir_all, write};
mod doc; mod doc;
mod tag;
mod visitor;
const GENERATED_COMMENT_TAG: &str = "@generated with lune-cli"; const GENERATED_COMMENT_TAG: &str = "@generated with lune-cli";
use self::{doc::DocsFunctionParamLink, visitor::DocumentationVisitor}; use self::doc::{DocsFunctionParamLink, DocumentationVisitor};
pub fn parse_definitions(contents: &str) -> Result<DocumentationVisitor> {
// TODO: Properly handle the "declare class" syntax, for now we just skip it
let mut no_declares = contents.to_string();
while let Some(dec) = no_declares.find("\ndeclare class") {
let end = no_declares.find("\nend").unwrap();
let before = &no_declares[0..dec];
let after = &no_declares[end + 4..];
no_declares = format!("{before}{after}");
}
let (regex, replacement) = (
Regex::new(r#"declare (?P<n>\w+): "#).unwrap(),
r#"export type $n = "#,
);
let defs_ast = parse_luau_ast(&regex.replace_all(&no_declares, replacement))?;
let mut visitor = DocumentationVisitor::new();
visitor.visit_ast(&defs_ast);
Ok(visitor)
}
pub fn generate_docs_json_from_definitions(contents: &str, namespace: &str) -> Result<String> { pub fn generate_docs_json_from_definitions(contents: &str, namespace: &str) -> Result<String> {
let visitor = parse_definitions(contents)?; let visitor = DocumentationVisitor::from_definitions(contents)?;
/* /*
Extract globals, functions, params, returns from the visitor Extract globals, functions, params, returns from the visitor
Here we will also convert the plain names into proper namespaced names according to the spec at Here we will also convert the plain names into proper namespaced names according to the spec at
https://raw.githubusercontent.com/MaximumADHD/Roblox-Client-Tracker/roblox/api-docs/en-us.json https://raw.githubusercontent.com/MaximumADHD/Roblox-Client-Tracker/roblox/api-docs/en-us.json
*/ */
let mut map = Map::new(); let mut map = JsonMap::new();
for (name, mut doc) in visitor.globals { for (name, mut doc) in visitor.globals {
doc.keys = doc doc.keys = doc
.keys .keys
@ -90,7 +67,7 @@ pub fn generate_docs_json_from_definitions(contents: &str, namespace: &str) -> R
serde_json::to_value(doc)?, serde_json::to_value(doc)?,
); );
} }
serde_json::to_string_pretty(&Value::Object(map)).context("Failed to encode docs as json") serde_json::to_string_pretty(&JsonValue::Object(map)).context("Failed to encode docs as json")
} }
pub async fn generate_wiki_dir_from_definitions(contents: &str) -> Result<()> { pub async fn generate_wiki_dir_from_definitions(contents: &str) -> Result<()> {
@ -102,7 +79,7 @@ pub async fn generate_wiki_dir_from_definitions(contents: &str) -> Result<()> {
create_dir_all(&root.join("wiki")) create_dir_all(&root.join("wiki"))
.await .await
.context("Failed to create wiki dir")?; .context("Failed to create wiki dir")?;
let visitor = parse_definitions(contents)?; let visitor = DocumentationVisitor::from_definitions(contents)?;
for global in &visitor.globals { for global in &visitor.globals {
// Create the dir for this global // Create the dir for this global
let global_dir_path = root.join("wiki").join("api-reference").join(&global.0); let global_dir_path = root.join("wiki").join("api-reference").join(&global.0);