Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public void NonRecursive()
{
List<string> folders = DirectoryScanner.GetFolders(folderPath,
new DirectoryScannerConfig() { ExcludeHiddenFolders = false, Recursive = false });
Assert.AreEqual(2, folders.Count);
Assert.AreEqual(3, folders.Count);
}

[Test]
Expand All @@ -29,15 +29,15 @@ public void Recursive()
{
List<string> folders = DirectoryScanner.GetFolders(folderPath,
new DirectoryScannerConfig() { ExcludeHiddenFolders = false, Recursive = true });
Assert.AreEqual(5, folders.Count);
Assert.AreEqual(8, folders.Count);
}

[Test]
public void RecursiveSearchPattern()
{
List<string> folders = DirectoryScanner.GetFolders(folderPath,
new DirectoryScannerConfig(searchPattern) { ExcludeHiddenFolders = false, Recursive = true });
Assert.AreEqual(2, folders.Count);
Assert.AreEqual(4, folders.Count);
}

[Test]
Expand All @@ -47,4 +47,28 @@ public void RecursiveExcludeHiddenFolders()
new DirectoryScannerConfig() { ExcludeHiddenFolders = true, Recursive = true });
Assert.AreEqual(4, folders.Count);
}

[Test]
public void RecursiveExcludeHiddenFoldersExtraSlashes()
{
List<string> folders = DirectoryScanner.GetFolders($"{Application.dataPath}/Editor/Tests//DirectoryScannerTest//",
new DirectoryScannerConfig() { ExcludeHiddenFolders = true, Recursive = true });
Assert.AreEqual(4, folders.Count);
}

[Test]
public void RecursiveDoNotExcludeHiddenFolderBeingScanned()
{
List<string> folders = DirectoryScanner.GetFolders($"{folderPath}.HiddenFolderC",
new DirectoryScannerConfig() { ExcludeHiddenFolders = true, Recursive = true });
Assert.AreEqual(2, folders.Count);
}

[Test]
public void RecursiveDoNotExcludeHiddenFoldersInParents()
{
List<string> folders = DirectoryScanner.GetFolders($"{folderPath}.HiddenFolderC/FolderC_A",
new DirectoryScannerConfig() { ExcludeHiddenFolders = true, Recursive = true });
Assert.AreEqual(1, folders.Count);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ public void Recursive()
{
List<string> files = FileScanner.GetFiles(folderPath,
new FileScannerConfig(txtFilePattern) { ExcludeHiddenFiles = false, ExcludeHiddenFolders = false, Recursive = true });
Assert.AreEqual(6, files.Count);
Assert.AreEqual(7, files.Count);
}

[Test]
public void RecursiveMultiplePatterns()
{
List<string> files = FileScanner.GetFiles(folderPath,
new FileScannerConfig(patterns) { ExcludeHiddenFiles = false, ExcludeHiddenFolders = false, Recursive = true });
Assert.AreEqual(12, files.Count);
Assert.AreEqual(14, files.Count);
}

[Test]
Expand All @@ -54,11 +54,35 @@ public void RecursiveExcludeHiddenFolders()
Assert.AreEqual(4, files.Count);
}

[Test]
public void RecursiveExcludeHiddenFoldersExtraSlashes()
{
List<string> files = FileScanner.GetFiles($"{Application.dataPath}/Editor/Tests//FileScannerTest//",
new FileScannerConfig(txtFilePattern) { ExcludeHiddenFiles = false, ExcludeHiddenFolders = true, Recursive = true });
Assert.AreEqual(4, files.Count);
}

[Test]
public void RecursiveDoNotExcludeHiddenFolderBeingScanned()
{
List<string> files = FileScanner.GetFiles($"{folderPath}.HiddenFolder",
new FileScannerConfig(txtFilePattern) { ExcludeHiddenFiles = false, ExcludeHiddenFolders = true, Recursive = true });
Assert.AreEqual(3, files.Count);
}

[Test]
public void RecursiveDoNotExcludeHiddenFoldersInParents()
{
List<string> files = FileScanner.GetFiles($"{folderPath}.HiddenFolder/SubfolderInHiddenFolder",
new FileScannerConfig(txtFilePattern) { ExcludeHiddenFiles = false, ExcludeHiddenFolders = true, Recursive = true });
Assert.AreEqual(1, files.Count);
}

[Test]
public void RecursiveExcludeHiddenFiles()
{
List<string> files = FileScanner.GetFiles(folderPath,
new FileScannerConfig(txtFilePattern) { ExcludeHiddenFiles = true, ExcludeHiddenFolders = false, Recursive = true });
Assert.AreEqual(5, files.Count);
Assert.AreEqual(6, files.Count);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,19 @@ public static List<string> GetFolders(string folder, DirectoryScannerConfig conf

List<string> filteredResult = unfilteredResult
// Ignore hidden folders
.Where(folderPath => (!config.ExcludeHiddenFolders || !IsHiddenFolder(folderPath)))
.Where(folderPath => (!config.ExcludeHiddenFolders || !IsHiddenFolder(folderPath, folder)))
.ToList();

return filteredResult;
}

private static bool IsHiddenFolder(string folderPath)
private static bool IsHiddenFolder(string folderPath, string rootPath)
{
// On Unix based operating systems, files and folders that start with a dot are hidden.
return folderPath.Contains("\\.") || folderPath.Contains("/.");
// Only check for hidden folders that are children of the root path, not the root path
// itself or its parents.
// We know rootPath is always a prefix of filePath, so it can be cut out with Substring().
folderPath = folderPath.Substring(rootPath.Length);
return folderPath.StartsWith(".") || folderPath.Contains("\\.") || folderPath.Contains("/.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public static List<string> GetFiles(string folder, FileScannerConfig config)
List<string> filteredResult = unfilteredResult
// Ignore hidden files and folders
.Where(filePath => (!config.ExcludeHiddenFiles || !IsHiddenFile(filePath))
&& (!config.ExcludeHiddenFolders || !IsInsideHiddenFolder(filePath)))
&& (!config.ExcludeHiddenFolders || !IsInsideHiddenFolder(filePath, folder)))
.ToList();

return filteredResult;
Expand All @@ -64,10 +64,15 @@ private static bool IsHiddenFile(string filePath)
return Path.GetFileName(filePath).StartsWith(".");
}

private static bool IsInsideHiddenFolder(string filePath)
private static bool IsInsideHiddenFolder(string filePath, string rootPath)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to have a common method for this. Currently, it is duplicated across DirectoryScanner and FileScanner.

Consider a HiddenFolderChecker or similar.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FileScanner and DirectoryScanner seem to be duplicates of each other anyway, they could probably be merged.

{
// On Unix based operating systems, files and folders that start with a dot are hidden.
string folderPath = Path.GetDirectoryName(filePath);
return folderPath.Contains("\\.") || folderPath.Contains("/.");
// Only check for hidden folders that are children of the root path, not the root path
// itself or its parents.
// We know rootPath is always a prefix of filePath, so it can be cut out with Substring().
// We also need to cut out the filename. Path.GetDirectoryName() can not be used here
// because it removes duplicate and trailing slashes, changing the string length.
string folderPath = filePath.Substring(rootPath.Length, filePath.LastIndexOfAny(new[] { '/', '\\' }) + 1 - rootPath.Length);
return folderPath.StartsWith(".") || folderPath.Contains("\\.") || folderPath.Contains("/.");

Copilot AI Mar 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hidden-folder detection via Contains(\"/.\") / Contains(\"\\\\.\") is brittle and mixes separator conventions; it’s easier to reason about (and less error-prone) if you split the (relative) path into segments and check segment.StartsWith('.') for each segment. If you keep the current approach, StartsWith(\".\") likely won’t match when the relative path begins with a separator (e.g., \"/.config\"), so consider trimming leading directory separators before applying StartsWith.

Suggested change
return folderPath.StartsWith(".") || folderPath.Contains("\\.") || folderPath.Contains("/.");
// Normalize the relative folder path and check each segment for a leading dot.
if (string.IsNullOrEmpty(folderPath))
{
return false;
}
folderPath = folderPath.TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
if (folderPath.Length == 0)
{
return false;
}
string[] segments = folderPath.Split(
new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar },
StringSplitOptions.RemoveEmptyEntries);
return segments.Any(segment => segment.StartsWith("."));

Copilot uses AI. Check for mistakes.
}
}
Loading