Rust library to generate static websites
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: match rolldown filename sanitization

+90 -1
+3 -1
crates/maudit/src/assets.rs
··· 9 9 mod image; 10 10 pub mod image_cache; 11 11 mod prefetch; 12 + mod sanitize_filename; 12 13 mod script; 13 14 mod style; 14 15 mod tailwind; ··· 413 414 414 415 fn make_filename(path: &Path, hash: &String, extension: Option<&str>) -> PathBuf { 415 416 let file_stem = path.file_stem().unwrap(); 417 + let sanitized_stem = sanitize_filename::default_sanitize_file_name(file_stem.to_str().unwrap()); 416 418 417 419 let mut filename = PathBuf::new(); 418 - filename.push(format!("{}.{}", file_stem.to_str().unwrap(), hash)); 420 + filename.push(format!("{}.{}", sanitized_stem, hash)); 419 421 420 422 if let Some(extension) = extension { 421 423 filename.set_extension(format!("{}.{}", hash, extension));
+87
crates/maudit/src/assets/sanitize_filename.rs
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2024-present VoidZero Inc. & Contributors 4 + 5 + // Permission is hereby granted, free of charge, to any person obtaining a copy 6 + // of this software and associated documentation files (the "Software"), to deal 7 + // in the Software without restriction, including without limitation the rights 8 + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + // copies of the Software, and to permit persons to whom the Software is 10 + // furnished to do so, subject to the following conditions: 11 + 12 + // The above copyright notice and this permission notice shall be included in all 13 + // copies or substantial portions of the Software. 14 + 15 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + // SOFTWARE. 22 + 23 + macro_rules! matches_invalid_chars { 24 + ($chars:ident) => { 25 + matches!($chars, 26 + '\u{0000}' 27 + ..='\u{001f}' 28 + | '"' 29 + | '#' 30 + | '$' 31 + | '%' 32 + | '&' 33 + | '*' 34 + | '+' 35 + | ',' 36 + | ':' 37 + | ';' 38 + | '<' 39 + | '=' 40 + | '>' 41 + | '?' 42 + | '[' 43 + | ']' 44 + | '^' 45 + | '`' 46 + | '{' 47 + | '|' 48 + | '}' 49 + | '\u{007f}' 50 + ) 51 + }; 52 + } 53 + 54 + // Follow from https://github.com/rollup/rollup/blob/master/src/utils/sanitizeFileName.ts 55 + pub fn default_sanitize_file_name(str: &str) -> String { 56 + let mut sanitized = String::with_capacity(str.len()); 57 + let mut chars = str.chars(); 58 + 59 + // A `:` is only allowed as part of a windows drive letter (ex: C:\foo) 60 + // Otherwise, avoid them because they can refer to NTFS alternate data streams. 61 + if starts_with_windows_drive(str) { 62 + sanitized.push(chars.next().unwrap()); 63 + sanitized.push(chars.next().unwrap()); 64 + } 65 + 66 + for char in chars { 67 + if matches_invalid_chars!(char) { 68 + sanitized.push('_'); 69 + } else { 70 + sanitized.push(char); 71 + } 72 + } 73 + sanitized 74 + } 75 + 76 + fn starts_with_windows_drive(str: &str) -> bool { 77 + let mut chars = str.chars(); 78 + if !chars.next().is_some_and(|c| c.is_ascii_alphabetic()) { 79 + return false; 80 + } 81 + chars.next().is_some_and(|c| c == ':') 82 + } 83 + 84 + #[test] 85 + fn test_sanitize_file_name() { 86 + assert_eq!(default_sanitize_file_name("\0+a=Z_0-"), "__a_Z_0-"); 87 + }