regex for file parsing
This commit is contained in:
@@ -38,7 +38,9 @@ pub mod types;
|
||||
// Re-exports
|
||||
pub use error::{Error, Result};
|
||||
pub use model::{RawDocument, UnityAsset, UnityFile, UnityPrefab, UnityScene};
|
||||
pub use parser::{find_project_root, meta::MetaFile, parse_unity_file, GuidResolver};
|
||||
pub use parser::{
|
||||
find_project_root, meta::MetaFile, parse_unity_file, parse_unity_file_filtered, GuidResolver,
|
||||
};
|
||||
// TODO: Re-enable once project module is updated
|
||||
// pub use project::UnityProject;
|
||||
pub use property::PropertyValue;
|
||||
|
||||
@@ -13,6 +13,7 @@ pub use yaml::split_yaml_documents;
|
||||
use crate::model::{RawDocument, UnityAsset, UnityFile, UnityPrefab, UnityScene};
|
||||
use crate::types::FileID;
|
||||
use crate::{Error, Result};
|
||||
use regex::Regex;
|
||||
use std::path::Path;
|
||||
|
||||
/// Parse a Unity file from the given path
|
||||
@@ -22,6 +23,8 @@ use std::path::Path;
|
||||
/// - .prefab → UnityFile::Prefab with raw YAML
|
||||
/// - .asset → UnityFile::Asset with raw YAML
|
||||
///
|
||||
/// By default, parses all files. Use `parse_unity_file_filtered` for regex filtering.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
@@ -38,6 +41,54 @@ use std::path::Path;
|
||||
/// # Ok::<(), cursebreaker_parser::Error>(())
|
||||
/// ```
|
||||
pub fn parse_unity_file(path: &Path) -> Result<UnityFile> {
|
||||
parse_unity_file_filtered(path, None)
|
||||
}
|
||||
|
||||
/// Parse a Unity file with optional regex filtering
|
||||
///
|
||||
/// Same as `parse_unity_file`, but allows filtering files by path pattern.
|
||||
/// If the path doesn't match the regex, returns an error.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `path` - Path to the Unity file to parse
|
||||
/// * `filter` - Optional regex to match against the file path. If None, parses all files (default behavior).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use cursebreaker_parser::parser::parse_unity_file_filtered;
|
||||
/// use regex::Regex;
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// // Only parse files with "Test" in the name
|
||||
/// let filter = Regex::new(r"Test").unwrap();
|
||||
/// let file = parse_unity_file_filtered(Path::new("TestScene.unity"), Some(&filter))?;
|
||||
///
|
||||
/// // Parse everything (same as parse_unity_file)
|
||||
/// let file2 = parse_unity_file_filtered(Path::new("Scene.unity"), None)?;
|
||||
/// # Ok::<(), cursebreaker_parser::Error>(())
|
||||
/// ```
|
||||
pub fn parse_unity_file_filtered(path: &Path, filter: Option<&Regex>) -> Result<UnityFile> {
|
||||
// Apply filter if provided
|
||||
if let Some(regex) = filter {
|
||||
let path_str = path.to_str().ok_or_else(|| {
|
||||
Error::invalid_format("Path contains invalid UTF-8")
|
||||
})?;
|
||||
|
||||
if !regex.is_match(path_str) {
|
||||
return Err(Error::invalid_format(format!(
|
||||
"Path '{}' does not match filter pattern",
|
||||
path.display()
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
parse_unity_file_impl(path)
|
||||
}
|
||||
|
||||
/// Internal implementation of Unity file parsing
|
||||
fn parse_unity_file_impl(path: &Path) -> Result<UnityFile> {
|
||||
// Read the file
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
|
||||
@@ -250,4 +301,89 @@ mod tests {
|
||||
FileType::Unknown
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_unity_file_filtered_accepts_matching_path() {
|
||||
use regex::Regex;
|
||||
|
||||
let filter = Regex::new(r"Test").unwrap();
|
||||
let path = Path::new("TestScene.unity");
|
||||
|
||||
// Should match and attempt to parse (will fail because file doesn't exist)
|
||||
let result = parse_unity_file_filtered(path, Some(&filter));
|
||||
assert!(result.is_err());
|
||||
|
||||
// Error should be IO error (file not found), not filter error
|
||||
match result {
|
||||
Err(e) => {
|
||||
let err_msg = e.to_string();
|
||||
assert!(
|
||||
!err_msg.contains("does not match filter"),
|
||||
"Should not be a filter error, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
Ok(_) => panic!("Expected error for non-existent file"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_unity_file_filtered_rejects_non_matching_path() {
|
||||
use regex::Regex;
|
||||
|
||||
let filter = Regex::new(r"Test").unwrap();
|
||||
let path = Path::new("MainScene.unity");
|
||||
|
||||
// Should reject due to filter
|
||||
let result = parse_unity_file_filtered(path, Some(&filter));
|
||||
assert!(result.is_err());
|
||||
|
||||
// Error should be filter error
|
||||
match result {
|
||||
Err(e) => {
|
||||
let err_msg = e.to_string();
|
||||
assert!(
|
||||
err_msg.contains("does not match filter"),
|
||||
"Expected filter error, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
Ok(_) => panic!("Expected filter error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_unity_file_filtered_none_accepts_all() {
|
||||
let path = Path::new("AnyScene.unity");
|
||||
|
||||
// No filter should accept any path (will fail with IO error)
|
||||
let result = parse_unity_file_filtered(path, None);
|
||||
assert!(result.is_err());
|
||||
|
||||
// Should be IO error, not filter error
|
||||
match result {
|
||||
Err(e) => {
|
||||
let err_msg = e.to_string();
|
||||
assert!(
|
||||
!err_msg.contains("does not match filter"),
|
||||
"Should not be a filter error with None filter, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
Ok(_) => panic!("Expected IO error for non-existent file"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_unity_file_uses_default_filter() {
|
||||
let path = Path::new("AnyScene.unity");
|
||||
|
||||
// parse_unity_file should work the same as filtered with None
|
||||
let result1 = parse_unity_file(path);
|
||||
let result2 = parse_unity_file_filtered(path, None);
|
||||
|
||||
// Both should have the same error (IO error for missing file)
|
||||
assert!(result1.is_err());
|
||||
assert!(result2.is_err());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user