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"
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",

View file

@ -23,9 +23,9 @@ panic = "abort" # Remove extra panic info
console = "0.15.5"
lazy_static = "1.4.0"
serde_json = "1.0.91"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.91", features = ["preserve_order"] }
tokio = { version = "1.24.2", features = ["full"] }
[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};
mod tag;
mod visitor;
pub use tag::*;
pub use visitor::*;
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
pub struct DocsGlobal {
pub documentation: String,

View file

@ -1,13 +1,15 @@
use anyhow::Result;
use full_moon::{
ast::types::{ExportedTypeDeclaration, TypeField, TypeFieldKey},
parse as parse_luau_ast,
tokenizer::{Token, TokenType},
visitors::Visitor,
};
use regex::Regex;
use super::{
doc::{DocsFunction, DocsFunctionParamLink, DocsGlobal, DocsParam, DocsReturn},
tag::{DocsTag, DocsTagKind, DocsTagList},
{DocsFunction, DocsFunctionParamLink, DocsGlobal, DocsParam, DocsReturn},
{DocsTag, DocsTagKind, DocsTagList},
};
#[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> {
if self.tag_regex.is_match(line) {
let captures = self.tag_regex.captures(line).unwrap();

View file

@ -1,47 +1,24 @@
use std::{collections::HashMap, fmt::Write, path::PathBuf};
use anyhow::{Context, Result};
use regex::Regex;
use serde_json::{Map, Value};
use serde_json::{Map as JsonMap, Value as JsonValue};
use full_moon::{parse as parse_luau_ast, visitors::Visitor};
use tokio::fs::{create_dir_all, write};
mod doc;
mod tag;
mod visitor;
const GENERATED_COMMENT_TAG: &str = "@generated with lune-cli";
use self::{doc::DocsFunctionParamLink, visitor::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)
}
use self::doc::{DocsFunctionParamLink, DocumentationVisitor};
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
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
*/
let mut map = Map::new();
let mut map = JsonMap::new();
for (name, mut doc) in visitor.globals {
doc.keys = doc
.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_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<()> {
@ -102,7 +79,7 @@ pub async fn generate_wiki_dir_from_definitions(contents: &str) -> Result<()> {
create_dir_all(&root.join("wiki"))
.await
.context("Failed to create wiki dir")?;
let visitor = parse_definitions(contents)?;
let visitor = DocumentationVisitor::from_definitions(contents)?;
for global in &visitor.globals {
// Create the dir for this global
let global_dir_path = root.join("wiki").join("api-reference").join(&global.0);