@@ -290,15 +290,29 @@ fn base64_encode(data: &[u8]) -> String {
292fn copy_non_hl_files(src_dir: &Path, out_dir: &Path) {
292fn copy_non_hl_files(src_dir: &Path, out_dir: &Path) {
293+ let skip = out_dir.canonicalize().ok();
293− copy_non_hl_recursive(src_dir, src_dir, out_dir);
294+ copy_non_hl_recursive(src_dir, src_dir, out_dir, skip.as_deref());
296−fn copy_non_hl_recursive(base: &Path, dir: &Path, out_dir: &Path) {
297+fn copy_non_hl_recursive(base: &Path, dir: &Path, out_dir: &Path, skip_canonical: Option<&Path>) {
297 if let Ok(entries) = fs::read_dir(dir) {
298 if let Ok(entries) = fs::read_dir(dir) {
298 for entry in entries.flatten() {
299 for entry in entries.flatten() {
299 let path = entry.path();
300 let path = entry.path();
300 if path.is_dir() {
301 if path.is_dir() {
302+ // Skip hidden directories (.htmlang-cache, .git, etc.)
305+ .is_some_and(|n| n.to_str().is_some_and(|s| s.starts_with('.')))
309+ // Skip the output directory to avoid copying it into itself
310+ if let Some(skip) = skip_canonical {
311+ if path.canonicalize().ok().as_deref() == Some(skip) {
301− copy_non_hl_recursive(base, &path, out_dir);
315+ copy_non_hl_recursive(base, &path, out_dir, skip_canonical);
302 } else if path.is_file() && path.extension().is_none_or(|e| e != "hl") {
316 } else if path.is_file() && path.extension().is_none_or(|e| e != "hl") {
303 let rel = path.strip_prefix(base).unwrap_or(&path);
317 let rel = path.strip_prefix(base).unwrap_or(&path);
304 let dest = out_dir.join(rel);
318 let dest = out_dir.join(rel);
@@ -518,6 +532,13 @@ fn collect_hl_recursive_inner(dir: &Path, files: &mut Vec<PathBuf>) {
518 for entry in entries.flatten() {
532 for entry in entries.flatten() {
519 let path = entry.path();
533 let path = entry.path();
520 if path.is_dir() {
534 if path.is_dir() {
535+ // Skip hidden directories (.htmlang-cache, .git, etc.)
538+ .is_some_and(|n| n.to_str().is_some_and(|s| s.starts_with('.')))
521 collect_hl_recursive_inner(&path, files);
542 collect_hl_recursive_inner(&path, files);
522 } else if path.is_file() && path.extension().is_some_and(|e| e == "hl") {
543 } else if path.is_file() && path.extension().is_some_and(|e| e == "hl") {
523 files.push(path);
544 files.push(path);
@@ -1220,7 +1241,7 @@ fn main() {
1220 let build_minify = build_minify || config.minify.unwrap_or(false);
1241 let build_minify = build_minify || config.minify.unwrap_or(false);
1221 let build_compat = build_compat || config.compat.unwrap_or(false);
1242 let build_compat = build_compat || config.compat.unwrap_or(false);
1222 let build_strict = build_strict || config.strict.unwrap_or(false);
1243 let build_strict = build_strict || config.strict.unwrap_or(false);
1223− let out_dir = out_dir.or(config.output.as_deref());
1244+ let out_dir = out_dir.or(config.output.as_deref()).or(Some("out"));
1224 let hl_files = collect_hl_files_recursive(dir);
1245 let hl_files = collect_hl_files_recursive(dir);
1225 if hl_files.is_empty() {
1246 if hl_files.is_empty() {
1226 eprintln!("no .hl files found in {}", src);
1247 eprintln!("no .hl files found in {}", src);