From 920e5ba5650d84f436f25d7702732969b2a38a94 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Mon, 22 Jan 2024 21:36:54 -0800
Subject: [PATCH] colossal fixes & tweaks

---
 src/main.rs | 94 ++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 64 insertions(+), 30 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index eb32583..0501bbf 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,6 +3,7 @@ use clap::{Args,Parser,Subcommand};
 use anyhow::Result as AResult;
 use futures::StreamExt;
 use rbx_dom_weak::types::Ref;
+use tokio::io::AsyncReadExt;
 
 type AssetID=u64;
 type AssetIDFileMap=Vec<(AssetID,std::path::PathBuf)>;
@@ -1140,23 +1141,29 @@ impl Query for QuerySingle{
 	}
 }
 struct QueryTriplet{
-	shared:QuerySingle,
+	module:QuerySingle,
 	server:QuerySingle,
 	client:QuerySingle,
 }
 impl QueryTriplet{
-	fn rox_rojo(search_path:&std::path::PathBuf,search_name:&str)->Self{
+	fn rox_rojo(search_path:&std::path::PathBuf,search_name:&str,search_module:bool)->Self{
+		//this should be implemented as constructors of Triplet and Quadruplet to fully support Trey's suggestion
+		let module_name=if search_module{
+			format!("{}.module.lua",search_name)
+		}else{
+			format!("{}.lua",search_name)
+		};
 		Self{
-			shared:QuerySingle(tokio::spawn(get_file_async(search_path.clone(),format!("{}.lua",search_name)))),
+			module:QuerySingle(tokio::spawn(get_file_async(search_path.clone(),module_name))),
 			server:QuerySingle(tokio::spawn(get_file_async(search_path.clone(),format!("{}.server.lua",search_name)))),
 			client:QuerySingle(tokio::spawn(get_file_async(search_path.clone(),format!("{}.client.lua",search_name)))),
 		}
 	}
-	fn rojo(search_path:&std::path::PathBuf,search_name:&str,is_subfolder:bool)->Self{
+	fn rojo(search_path:&std::path::PathBuf,search_name:&str,search_module:bool,is_subfolder:bool)->Self{
 		if is_subfolder{
-			QueryTriplet::rox_rojo(search_path,"init")
+			QueryTriplet::rox_rojo(search_path,"init",search_module)
 		}else{
-			QueryTriplet::rox_rojo(search_path,search_name)
+			QueryTriplet::rox_rojo(search_path,search_name,search_module)
 		}
 	}
 }
@@ -1181,42 +1188,69 @@ fn mega_triple_join(query_triplet:(QueryResult,QueryResult,QueryResult))->QueryR
 }
 impl Query for QueryTriplet{
 	async fn resolve(self)->Result<tokio::fs::File,QueryResolveError>{
-		let (shared,server,client)=tokio::join!(self.shared.0,self.server.0,self.client.0);
+		let (module,server,client)=tokio::join!(self.module.0,self.server.0,self.client.0);
 		mega_triple_join((
-			shared.map_err(|e|QueryResolveError::JoinError(e))?,
+			module.map_err(|e|QueryResolveError::JoinError(e))?,
 			server.map_err(|e|QueryResolveError::JoinError(e))?,
 			client.map_err(|e|QueryResolveError::JoinError(e))?,
 		))
 	}
 }
 
-async fn find_file(search_path:&std::path::PathBuf,search_name:&str,style:Option<DecompileStyle>)->AResult<CompileClass>{
-	//figure out something clever for this
-	let mut what=CompileNode{
-		class:CompileClass::Folder,
-		folder:None,
-	};
+async fn discern_node(search_path:&std::path::PathBuf,search_name:&str,style:Option<DecompileStyle>)->AResult<CompileNode>{
 	let mut contents_folder=search_path.clone();
 	contents_folder.push(search_name);
 	//folder
 	if let Ok(dir)=tokio::fs::read_dir(contents_folder.as_path()).await{
-		what.folder=Some(dir);
+		//scan inside the folder for an object to define the class of the folder
+		let (script_file,model_file)=tokio::join!(
+			async {match style{
+				Some(DecompileStyle::Rox)=>QuerySingle::rox(&contents_folder,search_name).resolve().await,
+				Some(DecompileStyle::RoxRojo)=>QueryTriplet::rox_rojo(&contents_folder,search_name,false).resolve().await,
+				Some(DecompileStyle::Rojo)=>QueryTriplet::rojo(&contents_folder,search_name,false,true).resolve().await,
+				//try all three and complain if there is ambiguity
+				None=>mega_triple_join(tokio::join!(
+					QuerySingle::rox(&contents_folder,search_name).resolve(),
+					//true=search for module here to avoid ambiguity with QuerySingle::rox results
+					QueryTriplet::rox_rojo(&contents_folder,search_name,true).resolve(),
+					QueryTriplet::rojo(&contents_folder,search_name,true,true).resolve(),
+				))
+			}},
+			//model files are rox & rox-rojo only, so it's a lot less work...
+			get_file_async(contents_folder.clone(),format!("{}.rbxmx",search_name))
+		);
+		//model? script? both?
+		Ok(match (script_file,model_file){
+			(Ok(mut file),Err(QueryResolveError::NotFound))=>{
+				//read entire file
+				let mut buf=String::new();
+				file.read_to_string(&mut buf).await?;
+				//regex script according to Properties lines at the top
+				todo!("unimplemented");
+				//script
+				CompileNode{
+					class:CompileClass::Script(buf),
+					folder:Some(dir),
+				}
+			},
+			(Err(QueryResolveError::NotFound),Ok(mut file))=>{
+				//read entire file
+				let mut buf=Vec::new();
+				file.read_to_end(&mut buf).await?;
+				//model
+				CompileNode{
+					class:CompileClass::Model(buf),
+					folder:Some(dir),
+				}
+			},
+			(Ok(_),Ok(_))=>Err(QueryResolveError::Ambiguous)?,
+			//other error
+			(Err(e),_)
+			|(_,Err(e))=>Err(e)?
+		})
 	}else{
-		contents_folder.pop();
+		Err(anyhow::Error::msg("message"))
 	}
-	let (script_file,model_file)=tokio::join!(async {match style{
-		Some(DecompileStyle::Rox)=>QuerySingle::rox(search_path,search_name).resolve().await,
-		Some(DecompileStyle::RoxRojo)=>QueryTriplet::rox_rojo(search_path,search_name).resolve().await,
-		Some(DecompileStyle::Rojo)=>QueryTriplet::rojo(search_path,search_name,what.folder.is_some()).resolve().await,
-		//try all three and complain if there is ambiguity
-		None=>mega_triple_join(tokio::join!(
-			QuerySingle::rox(search_path,search_name).resolve(),
-			QueryTriplet::rox_rojo(search_path,search_name).resolve(),
-			QueryTriplet::rojo(search_path,search_name,what.folder.is_some()).resolve(),
-		))
-	}},get_file_async(search_path.clone(),format!("{}.rbxmx",search_name)));
-
-	Ok(CompileClass::Folder)
 }
 
 enum CompileClass{
@@ -1267,7 +1301,7 @@ async fn compile(config:CompileConfig)->AResult<()>{
 			CompileStackInstruction::Referent(item_ref)=>{
 				let item=dom.get_by_ref(item_ref).ok_or(anyhow::Error::msg("null child ref"))?;
 				//check if item exists in folder or subfolder of same name
-				if let Ok(obj)=find_file(&folder,item.name.as_str(),None).await{
+				if let Ok(obj)=discern_node(&folder,item.name.as_str(),None).await{
 					//cool
 				}else{
 					//determine if this is ok