regex for file parsing

This commit is contained in:
2026-01-03 04:49:21 +00:00
parent 6f40cb9177
commit cd35339151
3 changed files with 566 additions and 1 deletions

View File

@@ -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;

View File

@@ -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());
}
}