diff --git a/Cargo.toml b/Cargo.toml index fe863a7ddf..9f17f79990 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ members = [ "crates/bevy_mod_scripting_derive", "crates/ladfile", "crates/lad_backends/mdbook_lad_preprocessor", + "crates/ladfile_builder", ] resolver = "2" exclude = ["crates/bevy_api_gen", "crates/macro_tests"] diff --git a/crates/lad_backends/mdbook_lad_preprocessor/src/sections.rs b/crates/lad_backends/mdbook_lad_preprocessor/src/sections.rs index 655c44f859..05ae6d4989 100644 --- a/crates/lad_backends/mdbook_lad_preprocessor/src/sections.rs +++ b/crates/lad_backends/mdbook_lad_preprocessor/src/sections.rs @@ -50,9 +50,20 @@ pub(crate) fn section_to_chapter( if let Some(original) = original_chapter { // override content only + log::debug!( + "Setting .md extension for chapter paths: {:?}, {:?}.", + original.path, + original.source_path + ); + Chapter { content: parent_builder.build(), sub_items: children_chapters, + path: original.path.as_ref().map(|p| p.with_extension("md")), + source_path: original + .source_path + .as_ref() + .map(|p| p.with_extension("md")), ..original.clone() } } else { @@ -119,7 +130,7 @@ impl Section<'_> { } pub(crate) fn file_name(&self) -> String { - self.title().to_lowercase().replace(" ", "_") + self.title().to_lowercase().replace(" ", "_") + ".md" } pub(crate) fn section_items(&self) -> Vec { diff --git a/crates/lad_backends/mdbook_lad_preprocessor/tests/book_integration_tests.rs b/crates/lad_backends/mdbook_lad_preprocessor/tests/book_integration_tests.rs index 8c5e206a53..9471fa6959 100644 --- a/crates/lad_backends/mdbook_lad_preprocessor/tests/book_integration_tests.rs +++ b/crates/lad_backends/mdbook_lad_preprocessor/tests/book_integration_tests.rs @@ -37,6 +37,20 @@ fn copy_ladfile_to_book_dir(book_dir: &std::path::Path, ladfile: &str) { std::fs::copy(ladfile_path, book_ladfile_path).expect("failed to copy LAD file"); } +fn all_files_in_dir_recursive(dir: &std::path::Path) -> Vec { + let mut files = vec![]; + for entry in std::fs::read_dir(dir).expect("failed to read dir") { + let entry = entry.expect("failed to get entry"); + let path = entry.path(); + if path.is_dir() { + files.extend(all_files_in_dir_recursive(&path)); + } else { + files.push(path); + } + } + files +} + #[test] fn test_on_example_ladfile() { // invoke mdbook build @@ -47,14 +61,35 @@ fn test_on_example_ladfile() { let books_dir = get_books_dir(); let book = "example_ladfile"; - let ladfile_path = "../../../../ladfile/test_assets/test.lad.json"; + let ladfile_path = "../../../../ladfile_builder/test_assets/test.lad.json"; copy_ladfile_to_book_dir(&books_dir.join(book), ladfile_path); Command::new("mdbook") - .env("RUST_LOG", "debug") + .env("RUST_LOG", "trace") .current_dir(books_dir.join(book)) .arg("build") .assert() .success(); + + // compare the sub directories (expected vs book in the book dir), existing files in expected must have a corresponding, identical file in the book dir with the same path + let expected_dir = books_dir.join(book).join("expected"); + let book_dir = books_dir.join(book).join("book"); + + let expected_files = all_files_in_dir_recursive(&expected_dir); + let book_files = all_files_in_dir_recursive(&book_dir); + + for expected_file in expected_files { + let relative_path = expected_file.strip_prefix(&expected_dir).unwrap(); + let book_file = book_dir.join(relative_path); + assert!( + book_files.contains(&book_file), + "File not found: {:?}", + book_file + ); + let expected_content = + std::fs::read_to_string(&expected_file).expect("failed to read file"); + let book_content = std::fs::read_to_string(&book_file).expect("failed to read file"); + pretty_assertions::assert_eq!(expected_content, book_content); + } } diff --git a/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/book.toml b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/book.toml index 2abfacddbc..0620453489 100644 --- a/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/book.toml +++ b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/book.toml @@ -8,3 +8,6 @@ description = "Documentation for the Bevy Scripting library" [preprocessor.lad-preprocessor] + + +[output.markdown] diff --git a/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/enumtype.md b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/enumtype.md new file mode 100644 index 0000000000..ffe22b2e1f --- /dev/null +++ b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/enumtype.md @@ -0,0 +1,21 @@ +# EnumType + +### Unit + +### Struct + +- **field** : usize + +### TupleStruct + +1. usize +2. String + +## Description + +> None available\. 🚧 + +## Functions + +| Function | Summary | +| --- | --- | diff --git a/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/structtype.md b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/structtype.md new file mode 100644 index 0000000000..bbf6f07196 --- /dev/null +++ b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/structtype.md @@ -0,0 +1,16 @@ +# StructType + +### StructType + +- **field** : usize +- **field2** : usize + +## Description + +> I am a struct + +## Functions + +| Function | Summary | +| --- | --- | +| `hello_world(ref_, tuple, option_vec_ref_wrapper)` | [No documentation available\. 🚧](#helloworld) | \ No newline at end of file diff --git a/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/tuplestructtype.md b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/tuplestructtype.md new file mode 100644 index 0000000000..a3b7079983 --- /dev/null +++ b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/tuplestructtype.md @@ -0,0 +1,15 @@ +# TupleStructType + +### TupleStructType + +1. usize +2. String + +## Description + +> I am a tuple test type + +## Functions + +| Function | Summary | +| --- | --- | diff --git a/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/unittype.md b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/unittype.md new file mode 100644 index 0000000000..2864cac1b5 --- /dev/null +++ b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/lad.md/unittype.md @@ -0,0 +1,14 @@ +# UnitType + +### UnitType + + + +## Description + +> I am a unit test type + +## Functions + +| Function | Summary | +| --- | --- | diff --git a/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/test.lad.md b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/test.lad.md new file mode 100644 index 0000000000..736b97b5db --- /dev/null +++ b/crates/lad_backends/mdbook_lad_preprocessor/tests/books/example_ladfile/expected/test.lad.md @@ -0,0 +1,17 @@ +# Nested Lad + +## Globals + +| Instance | Type | +| --- | --- | +| `my_static_instance` | ladfile\_builder::test::StructType | +| `my_non_static_instance` | ladfile\_builder::test::UnitType | + +## Types + +| Type | Summary | +| --- | --- | +| `EnumType` | [No documentation available\. 🚧](#enumtype) | +| `StructType` | [I am a struct](#structtype) | +| `TupleStructType` | [I am a tuple test type](#tuplestructtype) | +| `UnitType` | [I am a unit test type](#unittype) | \ No newline at end of file diff --git a/crates/ladfile/Cargo.toml b/crates/ladfile/Cargo.toml index 79d0e119ed..5da5077969 100644 --- a/crates/ladfile/Cargo.toml +++ b/crates/ladfile/Cargo.toml @@ -13,9 +13,6 @@ include = ["readme.md", "/src", "/test_assets"] readme = "readme.md" [dependencies] -bevy_mod_scripting_core = { workspace = true } -# I don't think bevy has a top level feature for this :C -bevy_reflect = { version = "0.15.2", features = ["documentation"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" indexmap = { version = "2.7", features = ["serde"] } diff --git a/crates/ladfile/src/lib.rs b/crates/ladfile/src/lib.rs index 2fe1fe8a46..5b89beb884 100644 --- a/crates/ladfile/src/lib.rs +++ b/crates/ladfile/src/lib.rs @@ -1,26 +1,11 @@ //! Parsing definitions for the LAD (Language Agnostic Decleration) file format. -use bevy_mod_scripting_core::{ - bindings::{ - function::{namespace::Namespace, script_function::FunctionCallContext}, - ReflectReference, - }, - docgen::{ - info::FunctionInfo, - typed_through::{ThroughTypeInfo, TypedWrapperKind, UntypedWrapperKind}, - }, - match_by_type, -}; -use bevy_reflect::{ - func::{DynamicFunction, DynamicFunctionMut}, - NamedField, Reflect, TypeInfo, TypeRegistry, Typed, UnnamedField, -}; use indexmap::IndexMap; -use std::{any::TypeId, borrow::Cow, collections::HashMap, ffi::OsString, path::PathBuf}; +use std::borrow::Cow; /// The current version of the LAD_VERSION format supported by this library. /// Earlier versions are not guaranteed to be supported. -const LAD_VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const LAD_VERSION: &str = env!("CARGO_PKG_VERSION"); #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] /// A Language Agnostic Declaration (LAD) file. @@ -177,7 +162,7 @@ pub struct LadBMSPrimitiveType { /// A primitive type kind in the LAD file format. /// /// The docstrings on variants corresponding to Reflect types, are used to generate documentation for these primitives. -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Reflect)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] #[allow(missing_docs)] pub enum LadBMSPrimitiveKind { @@ -245,41 +230,6 @@ impl LadBMSPrimitiveKind { } } } - - /// We can assume that the types here will be either primitives - /// or reflect types, as the rest will be covered by typed wrappers - /// so just check - fn from_type_id(type_id: TypeId) -> Option { - match_by_type!(match type_id { - i: bool => return Some(LadBMSPrimitiveKind::Bool), - i: isize => return Some(LadBMSPrimitiveKind::Isize), - i: i8 => return Some(LadBMSPrimitiveKind::I8), - i: i16 => return Some(LadBMSPrimitiveKind::I16), - i: i32 => return Some(LadBMSPrimitiveKind::I32), - i: i64 => return Some(LadBMSPrimitiveKind::I64), - i: i128 => return Some(LadBMSPrimitiveKind::I128), - i: usize => return Some(LadBMSPrimitiveKind::Usize), - i: u8 => return Some(LadBMSPrimitiveKind::U8), - i: u16 => return Some(LadBMSPrimitiveKind::U16), - i: u32 => return Some(LadBMSPrimitiveKind::U32), - i: u64 => return Some(LadBMSPrimitiveKind::U64), - i: u128 => return Some(LadBMSPrimitiveKind::U128), - i: f32 => return Some(LadBMSPrimitiveKind::F32), - i: f64 => return Some(LadBMSPrimitiveKind::F64), - i: char => return Some(LadBMSPrimitiveKind::Char), - i: &'static str => return Some(LadBMSPrimitiveKind::Str), - i: str => return Some(LadBMSPrimitiveKind::Str), - i: String => return Some(LadBMSPrimitiveKind::String), - i: OsString => return Some(LadBMSPrimitiveKind::OsString), - i: PathBuf => return Some(LadBMSPrimitiveKind::PathBuf), - i: FunctionCallContext => return Some(LadBMSPrimitiveKind::FunctionCallContext), - i: DynamicFunction => return Some(LadBMSPrimitiveKind::DynamicFunction), - i: DynamicFunctionMut => return Some(LadBMSPrimitiveKind::DynamicFunctionMut), - i: ReflectReference => return Some(LadBMSPrimitiveKind::ReflectReference) - }); - - None - } } #[derive( @@ -437,386 +387,6 @@ pub struct LadGeneric { pub name: String, } -/// A builder for constructing LAD files. -/// This should be your preferred way of constructing LAD files. -pub struct LadFileBuilder<'t> { - file: LadFile, - type_id_mapping: HashMap, - type_registry: &'t TypeRegistry, - sorted: bool, -} - -impl<'t> LadFileBuilder<'t> { - /// Create a new LAD file builder loaded with primitives. - pub fn new(type_registry: &'t TypeRegistry) -> Self { - let mut builder = Self { - file: LadFile::new(), - type_id_mapping: HashMap::new(), - type_registry, - sorted: false, - }; - - builder - .add_bms_primitive::("A boolean value") - .add_bms_primitive::("A signed pointer-sized integer") - .add_bms_primitive::("A signed 8-bit integer") - .add_bms_primitive::("A signed 16-bit integer") - .add_bms_primitive::("A signed 32-bit integer") - .add_bms_primitive::("A signed 64-bit integer") - .add_bms_primitive::("A signed 128-bit integer") - .add_bms_primitive::("An unsigned pointer-sized integer") - .add_bms_primitive::("An unsigned 8-bit integer") - .add_bms_primitive::("An unsigned 16-bit integer") - .add_bms_primitive::("An unsigned 32-bit integer") - .add_bms_primitive::("An unsigned 64-bit integer") - .add_bms_primitive::("An unsigned 128-bit integer") - .add_bms_primitive::("A 32-bit floating point number") - .add_bms_primitive::("A 64-bit floating point number") - .add_bms_primitive::("An 8-bit character") - .add_bms_primitive::<&'static str>("A string slice") - .add_bms_primitive::("A heap allocated string") - .add_bms_primitive::("A heap allocated OS string") - .add_bms_primitive::("A heap allocated file path") - .add_bms_primitive::("Function call context, if accepted by a function, means the function can access the world in arbitrary ways.") - .add_bms_primitive::("A callable dynamic function") - .add_bms_primitive::("A stateful and callable dynamic function") - .add_bms_primitive::("A reference to a reflectable type"); - - builder - } - - /// Set whether the LAD file should be sorted at build time. - pub fn set_sorted(&mut self, sorted: bool) -> &mut Self { - self.sorted = sorted; - self - } - - /// Add a BMS primitive to the LAD file. - /// Will do nothing if the type is not a BMS primitive. - pub fn add_bms_primitive( - &mut self, - docs: impl Into>, - ) -> &mut Self { - let type_id = self.lad_id_from_type_id(TypeId::of::()); - let kind = match LadBMSPrimitiveKind::from_type_id(TypeId::of::()) { - Some(primitive) => primitive, - None => return self, - }; - self.file.primitives.insert( - type_id, - LadBMSPrimitiveType { - kind, - documentation: docs.into(), - }, - ); - self - } - - /// Add a global instance to the LAD file. - /// - /// Requires the type to be registered via [`Self::add_type`] or [`Self::add_type_info`] first to provide rich type information. - /// - /// If `is_static` is true, the instance will be treated as a static instance - /// and hence not support method call syntax or method calls (i.e. only functions without a self parameter can be called on them). - pub fn add_instance( - &mut self, - key: impl Into>, - is_static: bool, - ) -> &mut Self { - let type_id = self.lad_id_from_type_id(TypeId::of::()); - self.file - .globals - .insert(key.into(), LadInstance { type_id, is_static }); - self - } - - /// Add a type definition to the LAD file. - /// - /// Equivalent to calling [`Self::add_type_info`] with `T::type_info()`. - pub fn add_type(&mut self) -> &mut Self { - self.add_type_info(T::type_info()); - self - } - - /// Add a type definition to the LAD file. - /// Will overwrite any existing type definitions with the same type id. - pub fn add_type_info(&mut self, type_info: &TypeInfo) -> &mut Self { - let type_id = self.lad_id_from_type_id(type_info.type_id()); - let lad_type = LadType { - identifier: type_info - .type_path_table() - .ident() - .unwrap_or_default() - .to_string(), - generics: type_info - .generics() - .iter() - .map(|param| LadGeneric { - type_id: self.lad_id_from_type_id(param.type_id()), - name: param.name().to_string(), - }) - .collect(), - documentation: type_info.docs().map(|s| s.to_string()), - associated_functions: Vec::new(), - crate_: type_info - .type_path_table() - .crate_name() - .map(|s| s.to_owned()), - path: type_info.type_path_table().path().to_owned(), - layout: self.lad_layout_from_type_info(type_info), - }; - self.file.types.insert(type_id, lad_type); - self - } - - /// Add a function definition to the LAD file. - /// Will overwrite any existing function definitions with the same function id. - pub fn add_function_info(&mut self, function_info: FunctionInfo) -> &mut Self { - let function_id = self.lad_function_id_from_info(&function_info); - let lad_function = LadFunction { - identifier: function_info.name, - arguments: function_info - .arg_info - .into_iter() - .map(|arg| { - let kind = match &arg.type_info { - Some(through_type) => { - self.lad_argument_type_from_through_type(through_type) - } - None => LadArgumentKind::Unknown(self.lad_id_from_type_id(arg.type_id)), - }; - LadArgument { - kind, - name: arg.name, - } - }) - .collect(), - return_type: self.lad_id_from_type_id(function_info.return_info.type_id), - documentation: function_info.docs, - namespace: match function_info.namespace { - Namespace::Global => LadFunctionNamespace::Global, - Namespace::OnType(type_id) => { - LadFunctionNamespace::Type(self.lad_id_from_type_id(type_id)) - } - }, - }; - self.file.functions.insert(function_id, lad_function); - self - } - - /// Set the markdown description of the LAD file. - pub fn set_description(&mut self, description: impl Into) -> &mut Self { - self.file.description = Some(description.into()); - self - } - - /// Build the finalized and optimized LAD file. - pub fn build(&mut self) -> LadFile { - let mut file = std::mem::replace(&mut self.file, LadFile::new()); - if self.sorted { - file.types.sort_keys(); - file.functions.sort_keys(); - file.primitives.sort_keys(); - } - - // associate functions on type namespaces with their types - for (function_id, function) in file.functions.iter() { - match &function.namespace { - LadFunctionNamespace::Type(type_id) => { - if let Some(t) = file.types.get_mut(type_id) { - t.associated_functions.push(function_id.clone()); - } - } - LadFunctionNamespace::Global => {} - } - } - - file - } - - fn variant_identifier_for_non_enum(type_info: &TypeInfo) -> Cow<'static, str> { - type_info - .type_path_table() - .ident() - .unwrap_or_else(|| type_info.type_path_table().path()) - .into() - } - - fn struct_variant_from_named_fields<'a, I: Iterator>( - &mut self, - name: Cow<'static, str>, - fields: I, - ) -> LadVariant { - LadVariant::Struct { - name, - fields: fields - .map(|field| LadNamedField { - name: field.name().to_string(), - type_: self.lad_id_from_type_id(field.type_id()), - }) - .collect(), - } - } - - fn tuple_struct_variant_from_fields<'a, I: Iterator>( - &mut self, - name: Cow<'static, str>, - fields: I, - ) -> LadVariant { - LadVariant::TupleStruct { - name, - fields: fields - .map(|field| LadField { - type_: self.lad_id_from_type_id(field.type_id()), - }) - .collect(), - } - } - - fn lad_layout_from_type_info(&mut self, type_info: &TypeInfo) -> LadTypeLayout { - match type_info { - TypeInfo::Struct(struct_info) => { - let fields = (0..struct_info.field_len()).filter_map(|i| struct_info.field_at(i)); - - LadTypeLayout::MonoVariant(self.struct_variant_from_named_fields( - Self::variant_identifier_for_non_enum(type_info), - fields, - )) - } - TypeInfo::TupleStruct(tuple_struct_info) => { - let fields = (0..tuple_struct_info.field_len()) - .filter_map(|i| tuple_struct_info.field_at(i)); - - LadTypeLayout::MonoVariant(self.tuple_struct_variant_from_fields( - Self::variant_identifier_for_non_enum(type_info), - fields, - )) - } - TypeInfo::Enum(enum_info) => { - let mut variants = Vec::new(); - for i in 0..enum_info.variant_len() { - if let Some(variant) = enum_info.variant_at(i) { - let variant_name = variant.name(); - let variant = match variant { - bevy_reflect::VariantInfo::Struct(struct_variant_info) => { - let fields = (0..struct_variant_info.field_len()) - .filter_map(|i| struct_variant_info.field_at(i)); - - self.struct_variant_from_named_fields(variant_name.into(), fields) - } - bevy_reflect::VariantInfo::Tuple(tuple_variant_info) => { - let fields = (0..tuple_variant_info.field_len()) - .filter_map(|i| tuple_variant_info.field_at(i)); - - self.tuple_struct_variant_from_fields(variant_name.into(), fields) - } - bevy_reflect::VariantInfo::Unit(_) => LadVariant::Unit { - name: variant_name.into(), - }, - }; - variants.push(variant); - } - } - LadTypeLayout::Enum(variants) - } - _ => LadTypeLayout::Opaque, - } - } - - fn lad_id_from_type_id(&mut self, type_id: TypeId) -> LadTypeId { - if let Some(lad_id) = self.type_id_mapping.get(&type_id) { - return lad_id.clone(); - } - - let new_id = match LadBMSPrimitiveKind::from_type_id(type_id) { - Some(primitive) => primitive.lad_type_id(), - None => { - if let Some(info) = self.type_registry.get_type_info(type_id) { - LadTypeId::new_string_id(info.type_path_table().path().into()) - } else { - LadTypeId::new_string_id(format!("{type_id:?}").into()) - } - } - }; - - self.type_id_mapping.insert(type_id, new_id.clone()); - new_id - } - - fn lad_function_id_from_info(&mut self, function_info: &FunctionInfo) -> LadFunctionId { - let namespace_string = match function_info.namespace { - bevy_mod_scripting_core::bindings::function::namespace::Namespace::Global => { - "".to_string() - } - bevy_mod_scripting_core::bindings::function::namespace::Namespace::OnType(type_id) => { - self.lad_id_from_type_id(type_id).0.to_string() - } - }; - - LadFunctionId::new_string_id(format!("{}::{}", namespace_string, function_info.name)) - } - - fn lad_argument_type_from_through_type( - &mut self, - through_type: &ThroughTypeInfo, - ) -> LadArgumentKind { - match through_type { - ThroughTypeInfo::UntypedWrapper { - through_type, - wrapper_kind, - .. - } => match wrapper_kind { - UntypedWrapperKind::Ref => { - LadArgumentKind::Ref(self.lad_id_from_type_id(through_type.type_id())) - } - UntypedWrapperKind::Mut => { - LadArgumentKind::Mut(self.lad_id_from_type_id(through_type.type_id())) - } - UntypedWrapperKind::Val => { - LadArgumentKind::Val(self.lad_id_from_type_id(through_type.type_id())) - } - }, - ThroughTypeInfo::TypedWrapper(typed_wrapper_kind) => match typed_wrapper_kind { - TypedWrapperKind::Vec(through_type_info) => LadArgumentKind::Vec(Box::new( - self.lad_argument_type_from_through_type(through_type_info), - )), - TypedWrapperKind::HashMap(through_type_info, through_type_info1) => { - LadArgumentKind::HashMap( - Box::new(self.lad_argument_type_from_through_type(through_type_info)), - Box::new(self.lad_argument_type_from_through_type(through_type_info1)), - ) - } - TypedWrapperKind::Array(through_type_info, size) => LadArgumentKind::Array( - Box::new(self.lad_argument_type_from_through_type(through_type_info)), - *size, - ), - TypedWrapperKind::Option(through_type_info) => LadArgumentKind::Option(Box::new( - self.lad_argument_type_from_through_type(through_type_info), - )), - TypedWrapperKind::InteropResult(through_type_info) => { - LadArgumentKind::InteropResult(Box::new( - self.lad_argument_type_from_through_type(through_type_info), - )) - } - TypedWrapperKind::Tuple(through_type_infos) => LadArgumentKind::Tuple( - through_type_infos - .iter() - .map(|through_type_info| { - self.lad_argument_type_from_through_type(through_type_info) - }) - .collect(), - ), - }, - ThroughTypeInfo::TypeInfo(type_info) => { - match LadBMSPrimitiveKind::from_type_id(type_info.type_id()) { - Some(primitive) => LadArgumentKind::Primitive(primitive), - None => LadArgumentKind::Unknown(self.lad_id_from_type_id(type_info.type_id())), - } - } - } - } -} - /// Parses a toml string into a LAD file. pub fn parse_lad_file(toml: &str) -> Result { serde_json::from_str(toml) @@ -830,137 +400,3 @@ pub fn serialize_lad_file(lad_file: &LadFile, pretty: bool) -> Result { - /// hello from field - field: usize, - /// hello from field 2 - field2: T, - } - - #[derive(Reflect)] - /// I am a unit test type - struct UnitType; - - #[derive(Reflect)] - /// I am a tuple test type - struct TupleStructType(pub usize, #[doc = "hello"] pub String); - - #[derive(Reflect)] - enum EnumType { - /// hello from variant - Unit, - /// hello from variant 2 - Struct { - /// hello from field - field: usize, - }, - /// hello from variant 3 - TupleStruct(usize, #[doc = "asd"] String), - } - - type_registry.register::>(); - type_registry.register::(); - type_registry.register::(); - type_registry.register::(); - - let function = |_: ReflectReference, _: usize| 2usize; - let function_info = function - .get_function_info("hello_world".into(), StructType::::into_namespace()) - .with_docs("hello docs"); - - let function_with_complex_args = - |_: ReflectReference, _: (usize, String), _: Option>>| 2usize; - let function_with_complex_args_info = function_with_complex_args - .get_function_info("hello_world".into(), StructType::::into_namespace()) - .with_arg_names(&["ref_", "tuple", "option_vec_ref_wrapper"]); - - let global_function = |_: usize| 2usize; - let global_function_info = global_function - .get_function_info("hello_world".into(), GlobalNamespace::into_namespace()) - .with_arg_names(&["arg1"]); - - let mut lad_file = LadFileBuilder::new(&type_registry) - .set_description("## Hello gentlemen\n I am markdown file.\n - hello\n - world") - .set_sorted(true) - .add_function_info(function_info) - .add_function_info(global_function_info) - .add_function_info(function_with_complex_args_info) - .add_type::>() - .add_type::() - .add_type::() - .add_type_info(EnumType::type_info()) - .add_instance::>("my_static_instance", true) - .add_instance::("my_non_static_instance", false) - .build(); - - // normalize the version so we don't have to update it every time - lad_file.version = "{{version}}".into(); - let mut serialized = serialize_lad_file(&lad_file, true).unwrap(); - - normalize_file(&mut serialized); - - if BLESS_TEST_FILE { - let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - let path_to_test_assets = std::path::Path::new(&manifest_dir).join("test_assets"); - - println!("Blessing test file at {:?}", path_to_test_assets); - std::fs::write(path_to_test_assets.join("test.lad.json"), &serialized).unwrap(); - return; - } - - let mut expected = include_str!("../test_assets/test.lad.json").to_owned(); - normalize_file(&mut expected); - - assert_eq!( - serialized.trim(), - expected.trim(), - "Expected:---\n {}\n---\nGot: ---\n{}\n---", - expected, - serialized - ); - } - - #[test] - fn test_asset_deserializes_correctly() { - let asset = include_str!("../test_assets/test.lad.json"); - let deserialized = parse_lad_file(asset).unwrap(); - assert_eq!(deserialized.version, "{{version}}"); - } -} diff --git a/crates/ladfile_builder/.gitignore b/crates/ladfile_builder/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/crates/ladfile_builder/.gitignore @@ -0,0 +1 @@ +/target diff --git a/crates/ladfile_builder/Cargo.toml b/crates/ladfile_builder/Cargo.toml new file mode 100644 index 0000000000..6ebcaef419 --- /dev/null +++ b/crates/ladfile_builder/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "ladfile_builder" +version = "0.2.0" +edition = "2021" +authors = ["Maksymilian Mozolewski "] +license = "MIT OR Apache-2.0" +description = "Language Agnostic Declaration (LAD) file format for the bevy_mod_scripting crate" +repository = "https://github.com/makspll/bevy_mod_scripting" +homepage = "https://github.com/makspll/bevy_mod_scripting" +keywords = ["bevy", "gamedev", "scripting", "format", "json"] +categories = ["game-development", "parser-implementations"] +include = ["readme.md", "/src", "/test_assets"] +readme = "readme.md" + +[dependencies] +bevy_mod_scripting_core = { workspace = true } +# I don't think bevy has a top level feature for this :C +bevy_reflect = { version = "0.15.2", features = ["documentation"] } +ladfile = { version = "0.2.0", path = "../ladfile" } + +[dev-dependencies] +pretty_assertions = "1.4" + +[lints] +workspace = true diff --git a/crates/ladfile_builder/readme.md b/crates/ladfile_builder/readme.md new file mode 100644 index 0000000000..08b05ead71 --- /dev/null +++ b/crates/ladfile_builder/readme.md @@ -0,0 +1,3 @@ +# Language Agnostic Declaration file builder + +Contains utilities for building LAD's using `bevy_mod_scripting_core` and `bevy`. \ No newline at end of file diff --git a/crates/ladfile_builder/src/lib.rs b/crates/ladfile_builder/src/lib.rs new file mode 100644 index 0000000000..150973d4f6 --- /dev/null +++ b/crates/ladfile_builder/src/lib.rs @@ -0,0 +1,561 @@ +//! Parsing definitions for the LAD (Language Agnostic Decleration) file format. + +use bevy_mod_scripting_core::{ + bindings::{ + function::{namespace::Namespace, script_function::FunctionCallContext}, + ReflectReference, + }, + docgen::{ + info::FunctionInfo, + typed_through::{ThroughTypeInfo, TypedWrapperKind, UntypedWrapperKind}, + }, + match_by_type, +}; +use bevy_reflect::{ + func::{DynamicFunction, DynamicFunctionMut}, + NamedField, TypeInfo, TypeRegistry, Typed, UnnamedField, +}; +use ladfile::*; +use std::{any::TypeId, borrow::Cow, collections::HashMap, ffi::OsString, path::PathBuf}; + +/// We can assume that the types here will be either primitives +/// or reflect types, as the rest will be covered by typed wrappers +/// so just check +fn primitive_from_type_id(type_id: TypeId) -> Option { + match_by_type!(match type_id { + i: bool => return Some(LadBMSPrimitiveKind::Bool), + i: isize => return Some(LadBMSPrimitiveKind::Isize), + i: i8 => return Some(LadBMSPrimitiveKind::I8), + i: i16 => return Some(LadBMSPrimitiveKind::I16), + i: i32 => return Some(LadBMSPrimitiveKind::I32), + i: i64 => return Some(LadBMSPrimitiveKind::I64), + i: i128 => return Some(LadBMSPrimitiveKind::I128), + i: usize => return Some(LadBMSPrimitiveKind::Usize), + i: u8 => return Some(LadBMSPrimitiveKind::U8), + i: u16 => return Some(LadBMSPrimitiveKind::U16), + i: u32 => return Some(LadBMSPrimitiveKind::U32), + i: u64 => return Some(LadBMSPrimitiveKind::U64), + i: u128 => return Some(LadBMSPrimitiveKind::U128), + i: f32 => return Some(LadBMSPrimitiveKind::F32), + i: f64 => return Some(LadBMSPrimitiveKind::F64), + i: char => return Some(LadBMSPrimitiveKind::Char), + i: &'static str => return Some(LadBMSPrimitiveKind::Str), + i: str => return Some(LadBMSPrimitiveKind::Str), + i: String => return Some(LadBMSPrimitiveKind::String), + i: OsString => return Some(LadBMSPrimitiveKind::OsString), + i: PathBuf => return Some(LadBMSPrimitiveKind::PathBuf), + i: FunctionCallContext => return Some(LadBMSPrimitiveKind::FunctionCallContext), + i: DynamicFunction => return Some(LadBMSPrimitiveKind::DynamicFunction), + i: DynamicFunctionMut => return Some(LadBMSPrimitiveKind::DynamicFunctionMut), + i: ReflectReference => return Some(LadBMSPrimitiveKind::ReflectReference) + }); + None +} + +/// A builder for constructing LAD files. +/// This should be your preferred way of constructing LAD files. +pub struct LadFileBuilder<'t> { + file: LadFile, + type_id_mapping: HashMap, + type_registry: &'t TypeRegistry, + sorted: bool, +} + +impl<'t> LadFileBuilder<'t> { + /// Create a new LAD file builder loaded with primitives. + pub fn new(type_registry: &'t TypeRegistry) -> Self { + let mut builder = Self { + file: LadFile::new(), + type_id_mapping: HashMap::new(), + type_registry, + sorted: false, + }; + + builder + .add_bms_primitive::("A boolean value") + .add_bms_primitive::("A signed pointer-sized integer") + .add_bms_primitive::("A signed 8-bit integer") + .add_bms_primitive::("A signed 16-bit integer") + .add_bms_primitive::("A signed 32-bit integer") + .add_bms_primitive::("A signed 64-bit integer") + .add_bms_primitive::("A signed 128-bit integer") + .add_bms_primitive::("An unsigned pointer-sized integer") + .add_bms_primitive::("An unsigned 8-bit integer") + .add_bms_primitive::("An unsigned 16-bit integer") + .add_bms_primitive::("An unsigned 32-bit integer") + .add_bms_primitive::("An unsigned 64-bit integer") + .add_bms_primitive::("An unsigned 128-bit integer") + .add_bms_primitive::("A 32-bit floating point number") + .add_bms_primitive::("A 64-bit floating point number") + .add_bms_primitive::("An 8-bit character") + .add_bms_primitive::<&'static str>("A string slice") + .add_bms_primitive::("A heap allocated string") + .add_bms_primitive::("A heap allocated OS string") + .add_bms_primitive::("A heap allocated file path") + .add_bms_primitive::("Function call context, if accepted by a function, means the function can access the world in arbitrary ways.") + .add_bms_primitive::("A callable dynamic function") + .add_bms_primitive::("A stateful and callable dynamic function") + .add_bms_primitive::("A reference to a reflectable type"); + + builder + } + + /// Set whether the LAD file should be sorted at build time. + pub fn set_sorted(&mut self, sorted: bool) -> &mut Self { + self.sorted = sorted; + self + } + + /// Add a BMS primitive to the LAD file. + /// Will do nothing if the type is not a BMS primitive. + pub fn add_bms_primitive( + &mut self, + docs: impl Into>, + ) -> &mut Self { + let type_id = self.lad_id_from_type_id(TypeId::of::()); + let kind = match primitive_from_type_id(TypeId::of::()) { + Some(primitive) => primitive, + None => return self, + }; + self.file.primitives.insert( + type_id, + LadBMSPrimitiveType { + kind, + documentation: docs.into(), + }, + ); + self + } + + /// Add a global instance to the LAD file. + /// + /// Requires the type to be registered via [`Self::add_type`] or [`Self::add_type_info`] first to provide rich type information. + /// + /// If `is_static` is true, the instance will be treated as a static instance + /// and hence not support method call syntax or method calls (i.e. only functions without a self parameter can be called on them). + pub fn add_instance( + &mut self, + key: impl Into>, + is_static: bool, + ) -> &mut Self { + let type_id = self.lad_id_from_type_id(TypeId::of::()); + self.file + .globals + .insert(key.into(), LadInstance { type_id, is_static }); + self + } + + /// Add a type definition to the LAD file. + /// + /// Equivalent to calling [`Self::add_type_info`] with `T::type_info()`. + pub fn add_type(&mut self) -> &mut Self { + self.add_type_info(T::type_info()); + self + } + + /// Add a type definition to the LAD file. + /// Will overwrite any existing type definitions with the same type id. + pub fn add_type_info(&mut self, type_info: &TypeInfo) -> &mut Self { + let type_id = self.lad_id_from_type_id(type_info.type_id()); + let lad_type = LadType { + identifier: type_info + .type_path_table() + .ident() + .unwrap_or_default() + .to_string(), + generics: type_info + .generics() + .iter() + .map(|param| LadGeneric { + type_id: self.lad_id_from_type_id(param.type_id()), + name: param.name().to_string(), + }) + .collect(), + documentation: type_info.docs().map(|s| s.to_string()), + associated_functions: Vec::new(), + crate_: type_info + .type_path_table() + .crate_name() + .map(|s| s.to_owned()), + path: type_info.type_path_table().path().to_owned(), + layout: self.lad_layout_from_type_info(type_info), + }; + self.file.types.insert(type_id, lad_type); + self + } + + /// Add a function definition to the LAD file. + /// Will overwrite any existing function definitions with the same function id. + pub fn add_function_info(&mut self, function_info: FunctionInfo) -> &mut Self { + let function_id = self.lad_function_id_from_info(&function_info); + let lad_function = LadFunction { + identifier: function_info.name, + arguments: function_info + .arg_info + .into_iter() + .map(|arg| { + let kind = match &arg.type_info { + Some(through_type) => { + self.lad_argument_type_from_through_type(through_type) + } + None => LadArgumentKind::Unknown(self.lad_id_from_type_id(arg.type_id)), + }; + LadArgument { + kind, + name: arg.name, + } + }) + .collect(), + return_type: self.lad_id_from_type_id(function_info.return_info.type_id), + documentation: function_info.docs, + namespace: match function_info.namespace { + Namespace::Global => LadFunctionNamespace::Global, + Namespace::OnType(type_id) => { + LadFunctionNamespace::Type(self.lad_id_from_type_id(type_id)) + } + }, + }; + self.file.functions.insert(function_id, lad_function); + self + } + + /// Set the markdown description of the LAD file. + pub fn set_description(&mut self, description: impl Into) -> &mut Self { + self.file.description = Some(description.into()); + self + } + + /// Build the finalized and optimized LAD file. + pub fn build(&mut self) -> LadFile { + let mut file = std::mem::replace(&mut self.file, LadFile::new()); + if self.sorted { + file.types.sort_keys(); + file.functions.sort_keys(); + file.primitives.sort_keys(); + } + + // associate functions on type namespaces with their types + for (function_id, function) in file.functions.iter() { + match &function.namespace { + LadFunctionNamespace::Type(type_id) => { + if let Some(t) = file.types.get_mut(type_id) { + t.associated_functions.push(function_id.clone()); + } + } + LadFunctionNamespace::Global => {} + } + } + + file + } + + fn variant_identifier_for_non_enum(type_info: &TypeInfo) -> Cow<'static, str> { + type_info + .type_path_table() + .ident() + .unwrap_or_else(|| type_info.type_path_table().path()) + .into() + } + + fn struct_variant_from_named_fields<'a, I: Iterator>( + &mut self, + name: Cow<'static, str>, + fields: I, + ) -> LadVariant { + LadVariant::Struct { + name, + fields: fields + .map(|field| LadNamedField { + name: field.name().to_string(), + type_: self.lad_id_from_type_id(field.type_id()), + }) + .collect(), + } + } + + fn tuple_struct_variant_from_fields<'a, I: Iterator>( + &mut self, + name: Cow<'static, str>, + fields: I, + ) -> LadVariant { + LadVariant::TupleStruct { + name, + fields: fields + .map(|field| LadField { + type_: self.lad_id_from_type_id(field.type_id()), + }) + .collect(), + } + } + + fn lad_layout_from_type_info(&mut self, type_info: &TypeInfo) -> LadTypeLayout { + match type_info { + TypeInfo::Struct(struct_info) => { + let fields = (0..struct_info.field_len()).filter_map(|i| struct_info.field_at(i)); + + LadTypeLayout::MonoVariant(self.struct_variant_from_named_fields( + Self::variant_identifier_for_non_enum(type_info), + fields, + )) + } + TypeInfo::TupleStruct(tuple_struct_info) => { + let fields = (0..tuple_struct_info.field_len()) + .filter_map(|i| tuple_struct_info.field_at(i)); + + LadTypeLayout::MonoVariant(self.tuple_struct_variant_from_fields( + Self::variant_identifier_for_non_enum(type_info), + fields, + )) + } + TypeInfo::Enum(enum_info) => { + let mut variants = Vec::new(); + for i in 0..enum_info.variant_len() { + if let Some(variant) = enum_info.variant_at(i) { + let variant_name = variant.name(); + let variant = match variant { + bevy_reflect::VariantInfo::Struct(struct_variant_info) => { + let fields = (0..struct_variant_info.field_len()) + .filter_map(|i| struct_variant_info.field_at(i)); + + self.struct_variant_from_named_fields(variant_name.into(), fields) + } + bevy_reflect::VariantInfo::Tuple(tuple_variant_info) => { + let fields = (0..tuple_variant_info.field_len()) + .filter_map(|i| tuple_variant_info.field_at(i)); + + self.tuple_struct_variant_from_fields(variant_name.into(), fields) + } + bevy_reflect::VariantInfo::Unit(_) => LadVariant::Unit { + name: variant_name.into(), + }, + }; + variants.push(variant); + } + } + LadTypeLayout::Enum(variants) + } + _ => LadTypeLayout::Opaque, + } + } + + fn lad_id_from_type_id(&mut self, type_id: TypeId) -> LadTypeId { + if let Some(lad_id) = self.type_id_mapping.get(&type_id) { + return lad_id.clone(); + } + + let new_id = match primitive_from_type_id(type_id) { + Some(primitive) => primitive.lad_type_id(), + None => { + if let Some(info) = self.type_registry.get_type_info(type_id) { + LadTypeId::new_string_id(info.type_path_table().path().into()) + } else { + LadTypeId::new_string_id(format!("{type_id:?}").into()) + } + } + }; + + self.type_id_mapping.insert(type_id, new_id.clone()); + new_id + } + + fn lad_function_id_from_info(&mut self, function_info: &FunctionInfo) -> LadFunctionId { + let namespace_string = match function_info.namespace { + bevy_mod_scripting_core::bindings::function::namespace::Namespace::Global => { + "".to_string() + } + bevy_mod_scripting_core::bindings::function::namespace::Namespace::OnType(type_id) => { + self.lad_id_from_type_id(type_id).to_string() + } + }; + + LadFunctionId::new_string_id(format!("{}::{}", namespace_string, function_info.name)) + } + + fn lad_argument_type_from_through_type( + &mut self, + through_type: &ThroughTypeInfo, + ) -> LadArgumentKind { + match through_type { + ThroughTypeInfo::UntypedWrapper { + through_type, + wrapper_kind, + .. + } => match wrapper_kind { + UntypedWrapperKind::Ref => { + LadArgumentKind::Ref(self.lad_id_from_type_id(through_type.type_id())) + } + UntypedWrapperKind::Mut => { + LadArgumentKind::Mut(self.lad_id_from_type_id(through_type.type_id())) + } + UntypedWrapperKind::Val => { + LadArgumentKind::Val(self.lad_id_from_type_id(through_type.type_id())) + } + }, + ThroughTypeInfo::TypedWrapper(typed_wrapper_kind) => match typed_wrapper_kind { + TypedWrapperKind::Vec(through_type_info) => LadArgumentKind::Vec(Box::new( + self.lad_argument_type_from_through_type(through_type_info), + )), + TypedWrapperKind::HashMap(through_type_info, through_type_info1) => { + LadArgumentKind::HashMap( + Box::new(self.lad_argument_type_from_through_type(through_type_info)), + Box::new(self.lad_argument_type_from_through_type(through_type_info1)), + ) + } + TypedWrapperKind::Array(through_type_info, size) => LadArgumentKind::Array( + Box::new(self.lad_argument_type_from_through_type(through_type_info)), + *size, + ), + TypedWrapperKind::Option(through_type_info) => LadArgumentKind::Option(Box::new( + self.lad_argument_type_from_through_type(through_type_info), + )), + TypedWrapperKind::InteropResult(through_type_info) => { + LadArgumentKind::InteropResult(Box::new( + self.lad_argument_type_from_through_type(through_type_info), + )) + } + TypedWrapperKind::Tuple(through_type_infos) => LadArgumentKind::Tuple( + through_type_infos + .iter() + .map(|through_type_info| { + self.lad_argument_type_from_through_type(through_type_info) + }) + .collect(), + ), + }, + ThroughTypeInfo::TypeInfo(type_info) => { + match primitive_from_type_id(type_info.type_id()) { + Some(primitive) => LadArgumentKind::Primitive(primitive), + None => LadArgumentKind::Unknown(self.lad_id_from_type_id(type_info.type_id())), + } + } + } + } +} + +#[cfg(test)] +mod test { + use bevy_mod_scripting_core::{ + bindings::function::{ + from::Ref, + namespace::{GlobalNamespace, IntoNamespace}, + }, + docgen::info::GetFunctionInfo, + }; + use bevy_reflect::Reflect; + + use super::*; + + /// Set to true to put output into test_assets. + const BLESS_TEST_FILE: bool = false; + + /// normalize line endings etc.. + fn normalize_file(file: &mut String) { + *file = file.replace("\r\n", "\n"); + } + + #[test] + fn test_empty_lad_file_serializes_correctly() { + let lad_file = LadFile::new(); + let serialized = serialize_lad_file(&lad_file, false).unwrap(); + let deserialized = parse_lad_file(&serialized).unwrap(); + assert_eq!(lad_file, deserialized); + assert_eq!(deserialized.version, ladfile::LAD_VERSION); + } + + #[test] + fn test_serializes_as_expected() { + let mut type_registry = TypeRegistry::default(); + + #[derive(Reflect)] + /// I am a struct + struct StructType { + /// hello from field + field: usize, + /// hello from field 2 + field2: T, + } + + #[derive(Reflect)] + /// I am a unit test type + struct UnitType; + + #[derive(Reflect)] + /// I am a tuple test type + struct TupleStructType(pub usize, #[doc = "hello"] pub String); + + #[derive(Reflect)] + enum EnumType { + /// hello from variant + Unit, + /// hello from variant 2 + Struct { + /// hello from field + field: usize, + }, + /// hello from variant 3 + TupleStruct(usize, #[doc = "asd"] String), + } + + type_registry.register::>(); + type_registry.register::(); + type_registry.register::(); + type_registry.register::(); + + let function = |_: ReflectReference, _: usize| 2usize; + let function_info = function + .get_function_info("hello_world".into(), StructType::::into_namespace()) + .with_docs("hello docs"); + + let function_with_complex_args = + |_: ReflectReference, _: (usize, String), _: Option>>| 2usize; + let function_with_complex_args_info = function_with_complex_args + .get_function_info("hello_world".into(), StructType::::into_namespace()) + .with_arg_names(&["ref_", "tuple", "option_vec_ref_wrapper"]); + + let global_function = |_: usize| 2usize; + let global_function_info = global_function + .get_function_info("hello_world".into(), GlobalNamespace::into_namespace()) + .with_arg_names(&["arg1"]); + + let mut lad_file = LadFileBuilder::new(&type_registry) + .set_description("## Hello gentlemen\n I am markdown file.\n - hello\n - world") + .set_sorted(true) + .add_function_info(function_info) + .add_function_info(global_function_info) + .add_function_info(function_with_complex_args_info) + .add_type::>() + .add_type::() + .add_type::() + .add_type_info(EnumType::type_info()) + .add_instance::>("my_static_instance", true) + .add_instance::("my_non_static_instance", false) + .build(); + + // normalize the version so we don't have to update it every time + lad_file.version = "{{version}}".into(); + let mut serialized = serialize_lad_file(&lad_file, true).unwrap(); + + normalize_file(&mut serialized); + + if BLESS_TEST_FILE { + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let path_to_test_assets = std::path::Path::new(&manifest_dir).join("test_assets"); + + println!("Blessing test file at {:?}", path_to_test_assets); + std::fs::write(path_to_test_assets.join("test.lad.json"), &serialized).unwrap(); + return; + } + + let mut expected = include_str!("../test_assets/test.lad.json").to_owned(); + normalize_file(&mut expected); + + pretty_assertions::assert_eq!(serialized.trim(), expected.trim(),); + } + + #[test] + fn test_asset_deserializes_correctly() { + let asset = include_str!("../test_assets/test.lad.json"); + let deserialized = parse_lad_file(asset).unwrap(); + assert_eq!(deserialized.version, "{{version}}"); + } +} diff --git a/crates/ladfile/test_assets/test.lad.json b/crates/ladfile_builder/test_assets/test.lad.json similarity index 85% rename from crates/ladfile/test_assets/test.lad.json rename to crates/ladfile_builder/test_assets/test.lad.json index d1e62337a7..990d6efce7 100644 --- a/crates/ladfile/test_assets/test.lad.json +++ b/crates/ladfile_builder/test_assets/test.lad.json @@ -2,19 +2,19 @@ "version": "{{version}}", "globals": { "my_static_instance": { - "type_id": "ladfile::test::StructType", + "type_id": "ladfile_builder::test::StructType", "is_static": true }, "my_non_static_instance": { - "type_id": "ladfile::test::UnitType", + "type_id": "ladfile_builder::test::UnitType", "is_static": false } }, "types": { - "ladfile::test::EnumType": { + "ladfile_builder::test::EnumType": { "identifier": "EnumType", - "crate": "ladfile", - "path": "ladfile::test::EnumType", + "crate": "ladfile_builder", + "path": "ladfile_builder::test::EnumType", "layout": [ { "kind": "Unit", @@ -44,10 +44,10 @@ } ] }, - "ladfile::test::StructType": { + "ladfile_builder::test::StructType": { "identifier": "StructType", - "crate": "ladfile", - "path": "ladfile::test::StructType", + "crate": "ladfile_builder", + "path": "ladfile_builder::test::StructType", "generics": [ { "type_id": "usize", @@ -56,7 +56,7 @@ ], "documentation": " I am a struct", "associated_functions": [ - "ladfile::test::StructType::hello_world" + "ladfile_builder::test::StructType::hello_world" ], "layout": { "kind": "Struct", @@ -73,10 +73,10 @@ ] } }, - "ladfile::test::TupleStructType": { + "ladfile_builder::test::TupleStructType": { "identifier": "TupleStructType", - "crate": "ladfile", - "path": "ladfile::test::TupleStructType", + "crate": "ladfile_builder", + "path": "ladfile_builder::test::TupleStructType", "documentation": " I am a tuple test type", "layout": { "kind": "TupleStruct", @@ -91,10 +91,10 @@ ] } }, - "ladfile::test::UnitType": { + "ladfile_builder::test::UnitType": { "identifier": "UnitType", - "crate": "ladfile", - "path": "ladfile::test::UnitType", + "crate": "ladfile_builder", + "path": "ladfile_builder::test::UnitType", "documentation": " I am a unit test type", "layout": { "kind": "Struct", @@ -116,8 +116,8 @@ ], "return_type": "usize" }, - "ladfile::test::StructType::hello_world": { - "namespace": "ladfile::test::StructType", + "ladfile_builder::test::StructType::hello_world": { + "namespace": "ladfile_builder::test::StructType", "identifier": "hello_world", "arguments": [ { @@ -143,7 +143,7 @@ "kind": { "option": { "vec": { - "ref": "ladfile::test::EnumType" + "ref": "ladfile_builder::test::EnumType" } } }, diff --git a/release-plz.toml b/release-plz.toml index bc0497d441..77411c22a2 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -77,3 +77,11 @@ git_release_latest = false git_tag_enable = true git_tag_name = "v{{ version }}-ladfile" git_release_name = "v{{ version }}-ladfile" + +[[package]] +name = "ladfile_builder" +git_release_enable = true +git_release_latest = false +git_tag_enable = true +git_tag_name = "v{{ version }}-ladfile_builder" +git_release_name = "v{{ version }}-ladfile_builder"