forked from rojo-rbx/rojo
name-prop (#1)
Reviewed-on: #1 Co-authored-by: ari <git@astrid.email> Co-committed-by: ari <git@astrid.email>
This commit was merged in pull request #1.
This commit is contained in:
@@ -8,11 +8,11 @@ use rbx_dom_weak::Instance;
|
||||
|
||||
use crate::{snapshot::InstanceWithMeta, snapshot_middleware::Middleware};
|
||||
|
||||
pub fn name_for_inst<'old>(
|
||||
pub fn name_for_inst<'a>(
|
||||
middleware: Middleware,
|
||||
new_inst: &Instance,
|
||||
old_inst: Option<InstanceWithMeta<'old>>,
|
||||
) -> anyhow::Result<Cow<'old, str>> {
|
||||
new_inst: &'a Instance,
|
||||
old_inst: Option<InstanceWithMeta<'a>>,
|
||||
) -> anyhow::Result<Cow<'a, str>> {
|
||||
if let Some(old_inst) = old_inst {
|
||||
if let Some(source) = old_inst.metadata().relevant_paths.first() {
|
||||
source
|
||||
@@ -35,14 +35,24 @@ pub fn name_for_inst<'old>(
|
||||
| Middleware::CsvDir
|
||||
| Middleware::ServerScriptDir
|
||||
| Middleware::ClientScriptDir
|
||||
| Middleware::ModuleScriptDir => Cow::Owned(new_inst.name.clone()),
|
||||
| Middleware::ModuleScriptDir => {
|
||||
if validate_file_name(&new_inst.name).is_err() {
|
||||
Cow::Owned(slugify_name(&new_inst.name))
|
||||
} else {
|
||||
Cow::Borrowed(&new_inst.name)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let extension = extension_for_middleware(middleware);
|
||||
let name = &new_inst.name;
|
||||
validate_file_name(name).with_context(|| {
|
||||
format!("name '{name}' is not legal to write to the file system")
|
||||
})?;
|
||||
Cow::Owned(format!("{name}.{extension}"))
|
||||
let slugified;
|
||||
let final_name = if validate_file_name(&new_inst.name).is_err() {
|
||||
slugified = slugify_name(&new_inst.name);
|
||||
&slugified
|
||||
} else {
|
||||
&new_inst.name
|
||||
};
|
||||
|
||||
Cow::Owned(format!("{final_name}.{extension}"))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -94,6 +104,39 @@ const INVALID_WINDOWS_NAMES: [&str; 22] = [
|
||||
/// in a file's name.
|
||||
const FORBIDDEN_CHARS: [char; 9] = ['<', '>', ':', '"', '/', '|', '?', '*', '\\'];
|
||||
|
||||
/// Slugifies a name by replacing forbidden characters with underscores
|
||||
/// and ensuring the result is a valid file name
|
||||
pub fn slugify_name(name: &str) -> String {
|
||||
let mut result = String::with_capacity(name.len());
|
||||
|
||||
for ch in name.chars() {
|
||||
if FORBIDDEN_CHARS.contains(&ch) {
|
||||
result.push('_');
|
||||
} else {
|
||||
result.push(ch);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Windows reserved names by appending an underscore
|
||||
let result_lower = result.to_lowercase();
|
||||
for forbidden in INVALID_WINDOWS_NAMES {
|
||||
if result_lower == forbidden.to_lowercase() {
|
||||
result.push('_');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while result.ends_with(' ') || result.ends_with('.') {
|
||||
result.pop();
|
||||
}
|
||||
|
||||
if result.is_empty() || result.chars().all(|c| c == '_') {
|
||||
result = "instance".to_string();
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Validates a provided file name to ensure it's allowed on the file system. An
|
||||
/// error is returned if the name isn't allowed, indicating why.
|
||||
/// This takes into account rules for Windows, MacOS, and Linux.
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::{
|
||||
Project,
|
||||
};
|
||||
|
||||
pub use file_names::{extension_for_middleware, name_for_inst, validate_file_name};
|
||||
pub use file_names::{extension_for_middleware, name_for_inst, slugify_name, validate_file_name};
|
||||
pub use fs_snapshot::FsSnapshot;
|
||||
pub use hash::*;
|
||||
pub use property_filter::{filter_properties, filter_properties_preallocated};
|
||||
|
||||
Reference in New Issue
Block a user