From c352f45eb9f8654f2a53b2c84c542fe8e12b3f3f Mon Sep 17 00:00:00 2001 From: rameel <rameel-b@hotmail.com> Date: Wed, 28 Aug 2024 18:33:17 +0500 Subject: [PATCH 1/6] Clean up --- .../FileProviderComposerTests.cs | 15 +++++++++++++-- .../Utilities/TestFileProvider.cs | 16 ---------------- 2 files changed, 13 insertions(+), 18 deletions(-) delete mode 100644 tests/Ramstack.FileProviders.Composition.Tests/Utilities/TestFileProvider.cs diff --git a/tests/Ramstack.FileProviders.Composition.Tests/FileProviderComposerTests.cs b/tests/Ramstack.FileProviders.Composition.Tests/FileProviderComposerTests.cs index 3f56f18..8eb0f39 100644 --- a/tests/Ramstack.FileProviders.Composition.Tests/FileProviderComposerTests.cs +++ b/tests/Ramstack.FileProviders.Composition.Tests/FileProviderComposerTests.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.FileProviders; - -using Ramstack.FileProviders.Composition.Utilities; +using Microsoft.Extensions.Primitives; namespace Ramstack.FileProviders.Composition; @@ -211,4 +210,16 @@ public void FlattenFileProvider_MaintainOrder_WhenComposite() Assert.That(provider, Is.InstanceOf<CompositeFileProvider>()); Assert.That(composite.FileProviders, Is.EquivalentTo(providers)); } + + private sealed class TestFileProvider : IFileProvider + { + public IFileInfo GetFileInfo(string subpath) => + new NotFoundFileInfo(subpath); + + public IDirectoryContents GetDirectoryContents(string subpath) => + NotFoundDirectoryContents.Singleton; + + public IChangeToken Watch(string? filter) => + NullChangeToken.Singleton; + } } diff --git a/tests/Ramstack.FileProviders.Composition.Tests/Utilities/TestFileProvider.cs b/tests/Ramstack.FileProviders.Composition.Tests/Utilities/TestFileProvider.cs deleted file mode 100644 index 753d845..0000000 --- a/tests/Ramstack.FileProviders.Composition.Tests/Utilities/TestFileProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Primitives; - -namespace Ramstack.FileProviders.Composition.Utilities; - -public sealed class TestFileProvider : IFileProvider -{ - public IFileInfo GetFileInfo(string subpath) => - new NotFoundFileInfo(subpath); - - public IDirectoryContents GetDirectoryContents(string subpath) => - NotFoundDirectoryContents.Singleton; - - public IChangeToken Watch(string? filter) => - NullChangeToken.Singleton; -} From cc957e8f44795bc983b8cc3f23808b4f98e5cdcd Mon Sep 17 00:00:00 2001 From: rameel <rameel-b@hotmail.com> Date: Wed, 28 Aug 2024 20:01:40 +0500 Subject: [PATCH 2/6] Update README --- README.md | 6 ++++++ src/Ramstack.FileProviders.Composition/README.md | 6 +++--- src/Ramstack.FileProviders.Extensions/README.md | 4 ++-- src/Ramstack.FileProviders.Globbing/README.md | 4 ++-- src/Ramstack.FileProviders/README.md | 4 ++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 815bb03..c5c82da 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,12 @@ foreach (FileNode file in provider.EnumerateFiles("/project", pattern: "**/*.md" RenderMarkdown(file); ``` +## Projects +- [Ramstack.FileProviders.Extensions](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) — Useful and convenient extensions for `IFileProvider`, bringing its capabilities and experience closer to what's provided by the `DirectoryInfo` and `FileInfo` classes. +- [Ramstack.FileProviders](https://www.nuget.org/packages/Ramstack.FileProviders) — Additional file providers, including `ZipFileProvider`, `PrefixedFileProvider`, and `SubFileProvider`. +- [Ramstack.FileProviders.Globbing](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) — A file provider that filters files using include and/or exclude glob patterns. Include patterns make only matching files visible, while exclude patterns hide specific files. Both include and exclude patterns can be combined for flexible file visibility control. +- [Ramstack.FileProviders.Composition](https://www.nuget.org/packages/Ramstack.FileProviders.Composition) — Provides a helper class for flattening and composing `IFileProvider`. + ## Supported versions | | Version | diff --git a/src/Ramstack.FileProviders.Composition/README.md b/src/Ramstack.FileProviders.Composition/README.md index 720272d..f5293f6 100644 --- a/src/Ramstack.FileProviders.Composition/README.md +++ b/src/Ramstack.FileProviders.Composition/README.md @@ -52,9 +52,9 @@ In this example, the `ComposeProviders` method handles any unnecessary nesting t flat structure, avoiding unnecessary indirectness. ## Related Packages -- [Ramstack.FileProviders](https://www.nuget.org/packages/Ramstack.FileProviders) — Additional file providers. -- [Ramstack.FileProviders.Globbing](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) — Wraps the file provider, filtering files using glob patterns. -- [Ramstack.FileProviders.Extensions](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) — Useful and convenient extensions for `IFileProvider`. +- [Ramstack.FileProviders.Extensions](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) — Useful and convenient extensions for `IFileProvider`, bringing its capabilities and experience closer to what's provided by the `DirectoryInfo` and `FileInfo` classes. +- [Ramstack.FileProviders](https://www.nuget.org/packages/Ramstack.FileProviders) — Additional file providers, including `ZipFileProvider`, `PrefixedFileProvider`, and `SubFileProvider`. +- [Ramstack.FileProviders.Globbing](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) — A file provider that filters files using include and/or exclude glob patterns. Include patterns make only matching files visible, while exclude patterns hide specific files. Both include and exclude patterns can be combined for flexible file visibility control. ## Supported versions diff --git a/src/Ramstack.FileProviders.Extensions/README.md b/src/Ramstack.FileProviders.Extensions/README.md index aa11b32..3ec9bc2 100644 --- a/src/Ramstack.FileProviders.Extensions/README.md +++ b/src/Ramstack.FileProviders.Extensions/README.md @@ -66,8 +66,8 @@ foreach (FileNode file in provider.EnumerateFiles("/project", pattern: "**/*.md" ``` ## Related Packages -- [Ramstack.FileProviders](https://www.nuget.org/packages/Ramstack.FileProviders) — Additional file providers. -- [Ramstack.FileProviders.Globbing](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) — Wraps the file provider, filtering files and directories using glob patterns. +- [Ramstack.FileProviders](https://www.nuget.org/packages/Ramstack.FileProviders) — Additional file providers, including `ZipFileProvider`, `PrefixedFileProvider`, and `SubFileProvider`. +- [Ramstack.FileProviders.Globbing](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) — A file provider that filters files using include and/or exclude glob patterns. Include patterns make only matching files visible, while exclude patterns hide specific files. Both include and exclude patterns can be combined for flexible file visibility control. - [Ramstack.FileProviders.Composition](https://www.nuget.org/packages/Ramstack.FileProviders.Composition) — Provides a helper class for flattening and composing `IFileProvider`. diff --git a/src/Ramstack.FileProviders.Globbing/README.md b/src/Ramstack.FileProviders.Globbing/README.md index fe9cbc6..23c94f7 100644 --- a/src/Ramstack.FileProviders.Globbing/README.md +++ b/src/Ramstack.FileProviders.Globbing/README.md @@ -24,8 +24,8 @@ foreach (IFileInfo file in provider.GetDirectoryContents("/")) ``` ## Related Packages -- [Ramstack.FileProviders](https://www.nuget.org/packages/Ramstack.FileProviders) — Additional file providers. -- [Ramstack.FileProviders.Extensions](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) — Useful and convenient extensions for `IFileProvider`. +- [Ramstack.FileProviders.Extensions](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) — Useful and convenient extensions for `IFileProvider`, bringing its capabilities and experience closer to what's provided by the `DirectoryInfo` and `FileInfo` classes. +- [Ramstack.FileProviders](https://www.nuget.org/packages/Ramstack.FileProviders) — Additional file providers, including `ZipFileProvider`, `PrefixedFileProvider`, and `SubFileProvider`. - [Ramstack.FileProviders.Composition](https://www.nuget.org/packages/Ramstack.FileProviders.Composition) — Provides a helper class for flattening and composing `IFileProvider`. diff --git a/src/Ramstack.FileProviders/README.md b/src/Ramstack.FileProviders/README.md index 78ab4ae..5592d12 100644 --- a/src/Ramstack.FileProviders/README.md +++ b/src/Ramstack.FileProviders/README.md @@ -92,8 +92,8 @@ foreach (IFileInfo file in provider.GetDirectoryContents("/")) ``` ## Related Packages -- [Ramstack.FileProviders.Extensions](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) — Useful and convenient extensions for `IFileProvider`. -- [Ramstack.FileProviders.Globbing](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) — Wraps the file provider, filtering files and directories using glob patterns. +- [Ramstack.FileProviders.Extensions](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) — Useful and convenient extensions for `IFileProvider`, bringing its capabilities and experience closer to what's provided by the `DirectoryInfo` and `FileInfo` classes. +- [Ramstack.FileProviders.Globbing](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) — A file provider that filters files using include and/or exclude glob patterns. Include patterns make only matching files visible, while exclude patterns hide specific files. Both include and exclude patterns can be combined for flexible file visibility control. - [Ramstack.FileProviders.Composition](https://www.nuget.org/packages/Ramstack.FileProviders.Composition) — Provides a helper class for flattening and composing `IFileProvider`. ## Supported versions From 3d42b6837838d1f0150e682546af48498b6e5c6c Mon Sep 17 00:00:00 2001 From: rameel <rameel-b@hotmail.com> Date: Wed, 28 Aug 2024 20:18:02 +0500 Subject: [PATCH 3/6] Update README --- README.md | 85 ++++++++++++++++--- src/Ramstack.FileProviders.Globbing/README.md | 7 +- .../Ramstack.FileProviders.Globbing.csproj | 2 +- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index c5c82da..02c5b4b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ <!-- TOC --> * [Ramstack.FileProviders](#ramstackfileproviders) * [Projects](#projects) + * [Ramstack.FileProviders.Extensions](#ramstackfileprovidersextensions) * [Ramstack.FileProviders](#ramstackfileproviders-1) * [Ramstack.FileProviders.Globbing](#ramstackfileprovidersglobbing) - * [Ramstack.FileProviders.Extensions](#ramstackfileprovidersextensions) + * [Ramstack.FileProviders.Composition](#ramstackfileproviderscomposition) * [Overview](#overview) * [Ramstack.FileProviders](#ramstackfileproviders-2) * [PrefixedFileProvider](#prefixedfileprovider) @@ -11,6 +12,10 @@ * [ZipFileProvider](#zipfileprovider) * [Ramstack.FileProviders.Globbing](#ramstackfileprovidersglobbing-1) * [Ramstack.FileProviders.Extensions](#ramstackfileprovidersextensions-1) + * [Ramstack.FileProviders.Composition](#ramstackfileproviderscomposition-1) + * [Flattening Providers](#flattening-providers) + * [Composing Providers](#composing-providers) + * [Projects](#projects-1) * [Supported versions](#supported-versions) * [Contributions](#contributions) * [License](#license) @@ -23,30 +28,44 @@ building upon `Microsoft.Extensions.FileProviders`. ## Projects -This repository contains three main projects: +This repository contains projects: + +### Ramstack.FileProviders.Extensions +Offers useful and convenient extensions for `IFileProviders`, bringing its capabilities and experience +closer to what's provided by the `DirectoryInfo` and `FileInfo` standard classes. + +To install the `Ramstack.FileProviders.Extensions` [NuGet package](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) in your project, +run the following command: +```console +dotnet add package Ramstack.FileProviders.Extensions +``` ### Ramstack.FileProviders Provides additional implementations of `IFileProvider` including `PrefixedFileProvider`, `SubFileProvider`, and `ZipFileProvider`. -To install the `Ramstack.FileProviders` [NuGet package](https://www.nuget.org/packages/Ramstack.FileProviders) in your project, run the following command: +To install the `Ramstack.FileProviders` [NuGet package](https://www.nuget.org/packages/Ramstack.FileProviders) in your project, +run the following command: ```console dotnet add package Ramstack.FileProviders ``` ### Ramstack.FileProviders.Globbing -Represents a .NET library implementing an `IFileProvider` that applies glob-based filtering rules to determine which files to include or exclude. +Represents a .NET library implementing an `IFileProvider` that filters files using include and/or exclude glob patterns +for flexible file visibility control. -To install the `Ramstack.FileProviders.Globbing` [NuGet package](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) in your project, run the following command: +To install the `Ramstack.FileProviders.Globbing` [NuGet package](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) in your project, +run the following command: ```console dotnet add package Ramstack.FileProviders.Globbing ``` -### Ramstack.FileProviders.Extensions -Offers useful and convenient extensions for `Microsoft.Extensions.FileProviders`. +### Ramstack.FileProviders.Composition +Provides a helper class for flattening and composing `IFileProvider` instances. -To install the `Ramstack.FileProviders.Extensions` [NuGet package](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) in your project, run the following command: +To install the `Ramstack.FileProviders.Composition` [NuGet package](https://www.nuget.org/packages/Ramstack.FileProviders.Composition) in your project, +run the following command: ```console -dotnet add package Ramstack.FileProviders.Extensions +dotnet add package Ramstack.FileProviders.Composition ``` ## Overview @@ -138,8 +157,8 @@ foreach (IFileInfo file in provider.GetDirectoryContents("/")) ### Ramstack.FileProviders.Globbing -`GlobbingFileProvider` class supports glob pattern matching for file paths, allowing for flexible file selection. You can specify patterns -for both including and excluding files. +`GlobbingFileProvider` class filters files using include and/or exclude glob patterns. Include patterns make only matching files visible, +while exclude patterns hide specific files. Both include and exclude patterns can be combined for flexible file visibility control. It relies on the [Ramstack.Globbing](https://www.nuget.org/packages/Ramstack.Globbing) package for its globbing capabilities. @@ -205,6 +224,50 @@ foreach (FileNode file in provider.EnumerateFiles("/project", pattern: "**/*.md" RenderMarkdown(file); ``` +### Ramstack.FileProviders.Composition + +#### Flattening Providers +The `FlattenProvider` method attempts to flatten a given `IFileProvider` into a single list of file providers. + +This is especially useful when dealing with nested `CompositeFileProvider` instances, which might have been created during +different stages of a pipeline or configuration. Flattening helps in removing unnecessary indirectness and improving efficiency +by consolidating all file providers into a single level. + +```csharp +var builder = WebApplication.CreateBuilder(args); + +// Application pipeline configuration +... + +builder.Environment.ContentRootFileProvider = FileProviderComposer.FlattenProvider( + builder.Environment.ContentRootFileProvider); +``` + +#### Composing Providers +The `ComposeProviders` method combines a list of `IFileProvider` instances into a single `IFileProvider`. +During this process, all encountered `CompositeFileProvider` instances recursively flattened and merged into a single level. +This eliminates unnecessary indirectness and streamline the file provider hierarchy. + +```csharp +string packagesPath = Path.Combine(environment.ContentRootPath, "../Packages"); +string themesPath = Path.Combine(environment.ContentRootPath, "../Themes"); + +environment.ContentRootFileProvider = FileProviderComposer.ComposeProviders( + // Inject external Modules directory + new PrefixedFileProvider("/Packages", new PhysicalFileProvider(packagesPath)), + + // Inject external Themes directory + new PrefixedFileProvider("/Themes", new PhysicalFileProvider(themesPath)), + + // Current provider + environment.ContentRootFileProvider); +``` + +In this example, the `ComposeProviders` method handles any unnecessary nesting that might occur, including when the current +`environment.ContentRootFileProvider` is a `CompositeFileProvider`. This ensures that all file providers merged into a single +flat structure, avoiding unnecessary indirectness. + + ## Projects - [Ramstack.FileProviders.Extensions](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) — Useful and convenient extensions for `IFileProvider`, bringing its capabilities and experience closer to what's provided by the `DirectoryInfo` and `FileInfo` classes. - [Ramstack.FileProviders](https://www.nuget.org/packages/Ramstack.FileProviders) — Additional file providers, including `ZipFileProvider`, `PrefixedFileProvider`, and `SubFileProvider`. diff --git a/src/Ramstack.FileProviders.Globbing/README.md b/src/Ramstack.FileProviders.Globbing/README.md index 23c94f7..635cfbe 100644 --- a/src/Ramstack.FileProviders.Globbing/README.md +++ b/src/Ramstack.FileProviders.Globbing/README.md @@ -1,6 +1,7 @@ # Ramstack.FileProviders.Globbing -Represents a .NET library implementing an `IFileProvider` that applies glob-based filtering rules to determine which files to include or exclude. +Represents a .NET library implementing an `IFileProvider` that filters files using include and/or exclude glob patterns +for flexible file visibility control. ## Getting Started @@ -11,8 +12,8 @@ dotnet add package Ramstack.FileProviders.Globbing ``` ## GlobbingFileProvider -`GlobbingFileProvider` class supports glob pattern matching for file paths, allowing for flexible file selection. -You can specify patterns for both including and excluding files. +`GlobbingFileProvider` class filters files using include and/or exclude glob patterns. Include patterns make only matching files visible, +while exclude patterns hide specific files. Both include and exclude patterns can be combined for flexible file visibility control. It relies on the [Ramstack.Globbing](https://www.nuget.org/packages/Ramstack.Globbing) package for its globbing capabilities. diff --git a/src/Ramstack.FileProviders.Globbing/Ramstack.FileProviders.Globbing.csproj b/src/Ramstack.FileProviders.Globbing/Ramstack.FileProviders.Globbing.csproj index 6071e0a..fa07b9f 100644 --- a/src/Ramstack.FileProviders.Globbing/Ramstack.FileProviders.Globbing.csproj +++ b/src/Ramstack.FileProviders.Globbing/Ramstack.FileProviders.Globbing.csproj @@ -2,7 +2,7 @@ <PropertyGroup> <TargetFramework>net6.0</TargetFramework> - <Description>A .NET library implementing a Microsoft.Extensions.FileProviders that filters files based on glob patterns.</Description> + <Description>A .NET library implementing a IFileProvider that filters files using include and/or exclude glob patterns.</Description> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <LangVersion>preview</LangVersion> From a1e5c411430358f7af76c0fd653a585b677ee02b Mon Sep 17 00:00:00 2001 From: rameel <rameel-b@hotmail.com> Date: Wed, 28 Aug 2024 20:19:33 +0500 Subject: [PATCH 4/6] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 02c5b4b..44f7e6f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ * [Ramstack.FileProviders.Composition](#ramstackfileproviderscomposition-1) * [Flattening Providers](#flattening-providers) * [Composing Providers](#composing-providers) - * [Projects](#projects-1) + * [NuGet Packages](#nuget-packages) * [Supported versions](#supported-versions) * [Contributions](#contributions) * [License](#license) @@ -268,7 +268,7 @@ In this example, the `ComposeProviders` method handles any unnecessary nesting t flat structure, avoiding unnecessary indirectness. -## Projects +## NuGet Packages - [Ramstack.FileProviders.Extensions](https://www.nuget.org/packages/Ramstack.FileProviders.Extensions) — Useful and convenient extensions for `IFileProvider`, bringing its capabilities and experience closer to what's provided by the `DirectoryInfo` and `FileInfo` classes. - [Ramstack.FileProviders](https://www.nuget.org/packages/Ramstack.FileProviders) — Additional file providers, including `ZipFileProvider`, `PrefixedFileProvider`, and `SubFileProvider`. - [Ramstack.FileProviders.Globbing](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) — A file provider that filters files using include and/or exclude glob patterns. Include patterns make only matching files visible, while exclude patterns hide specific files. Both include and exclude patterns can be combined for flexible file visibility control. From a626ae4e3d670a1a72ffd7cc43fd87d73a71672a Mon Sep 17 00:00:00 2001 From: rameel <rameel-b@hotmail.com> Date: Wed, 28 Aug 2024 20:24:18 +0500 Subject: [PATCH 5/6] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 44f7e6f..5e86658 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ dotnet add package Ramstack.FileProviders ``` ### Ramstack.FileProviders.Globbing -Represents a .NET library implementing an `IFileProvider` that filters files using include and/or exclude glob patterns +Provides an implementation of the `IFileProvider` that filters files using include and/or exclude glob patterns for flexible file visibility control. To install the `Ramstack.FileProviders.Globbing` [NuGet package](https://www.nuget.org/packages/Ramstack.FileProviders.Globbing) in your project, From 86b3a7c87812145bb7fd1a57c8319189f9831c9c Mon Sep 17 00:00:00 2001 From: rameel <rameel-b@hotmail.com> Date: Wed, 28 Aug 2024 20:28:24 +0500 Subject: [PATCH 6/6] Update README --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e86658..287fe24 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ as if they were originally defined within your project. ``` #### SubFileProvider + `SubFileProvider` lets you limit the view of the file system to a specific subdirectory, effectively creating a sandbox. Example: @@ -146,6 +147,7 @@ Console.WriteLine(file.Exists); ``` #### ZipFileProvider + `ZipFileProvider` enables access to files within ZIP archives as if they were part of the file system. Example: @@ -171,7 +173,7 @@ foreach (IFileInfo file in provider.GetDirectoryContents("/")) ### Ramstack.FileProviders.Extensions -The library provides useful extensions for `IFileProvider`, bringing its capabilities and experience closer to what's being +Provides useful extensions for `IFileProvider`, bringing its capabilities and experience closer to what's being provided by `DirectoryInfo` and `FileInfo` classes. Simply stated, a `FileNode` knows which directory it is located in, and a directory represented by the `DirectoryNode` class can access @@ -226,7 +228,10 @@ foreach (FileNode file in provider.EnumerateFiles("/project", pattern: "**/*.md" ### Ramstack.FileProviders.Composition +Provides a helper class `FileProviderComposer` for flattening and composing `IFileProvider` instances. + #### Flattening Providers + The `FlattenProvider` method attempts to flatten a given `IFileProvider` into a single list of file providers. This is especially useful when dealing with nested `CompositeFileProvider` instances, which might have been created during @@ -244,6 +249,7 @@ builder.Environment.ContentRootFileProvider = FileProviderComposer.FlattenProvid ``` #### Composing Providers + The `ComposeProviders` method combines a list of `IFileProvider` instances into a single `IFileProvider`. During this process, all encountered `CompositeFileProvider` instances recursively flattened and merged into a single level. This eliminates unnecessary indirectness and streamline the file provider hierarchy.