microsoft / microsoft/vs-solutionpersistence

[Feature Request] Allow Folders within Folders

Open
#140 0 comments 7 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
213
Forks
14
PR merge metrics
No merged PRs in 30d

Description

Currently, Folder elements may only contain File, Project or Properties elements. Allowing Folder elements within Folder elements would make the .slnx file a lot less repetitive, and increase readability.

Proposal

  • Allow for <Folder> elements within other <Folder> elements
  • When a child Folder is within a parent Folder, the child's Name attribute becomes relative to the parent's Name
    • ie:
      <Folder Name="/ParentFolder/" />
      <Folder Name="/ParentFolder/ChildFolder/" />
      
      would be written as
      <Folder Name="/ParentFolder/">
        <Folder Name="ChildFolder/" />
      </Folder>
      

Motivation

  • It would allow the .slnx file to mirror the structure of the solution within Visual Studio.
    • When viewed from an external tool (such as PR diff tools or text editors), it would allow one to parse the structure of the solution a lot quicker.

Example Usage

Let's say we have a mono-repo solution, here's how the .slnx file would change, should this feature get implemented.

before:
Solution.slnx
<Solution>
  <Folder Name="/Solution Items/">
    <File Path=".gitignore" />
    <File Path="Directory.Build.props" />
    <File Path="Directory.Packages.props" />
    <File Path="README.md" />
  </Folder>
  <Folder Name="/Services/">
    <File Path="src/Services/Directory.Build.props" />
  </Folder>
  <Folder Name="/Services/SomeDomain1/">
    <File Path="src/Services/SomeDomain1/SomeDomain1.slnx" />
    <File Path="src/Services/SomeDomain1/Directory.Build.props" />
  </Folder>
  <Folder Name="/Services/SomeDomain1/ApplicationLayer/">
    <Project Path="src/Services/SomeDomain1/src/SomeDomain1.ApplicationLayer/SomeDomain1.ApplicationLayer.csproj" />
    <Project Path="src/Services/SomeDomain1/tests/SomeDomain1.ApplicationLayer/SomeDomain1.ApplicationLayer.UnitTests.csproj" />
  </Folder>
  <Folder Name="/Services/SomeDomain1/Infrastructure/">
    <Project Path="src/Services/SomeDomain1/src/SomeDomain1.Infrastructure/SomeDomain1.Infrastructure.csproj" />
    <Project Path="src/Services/SomeDomain1/tests/SomeDomain1.Infrastructure/SomeDomain1.Infrastructure.UnitTests.csproj" />
  </Folder>
  <Folder Name="/Services/SomeDomain1/Service/">
    <Project Path="src/Services/SomeDomain1/src/SomeDomain1.Service/SomeDomain1.Service.csproj" />
    <Project Path="src/Services/SomeDomain1/tests/SomeDomain1.Service/SomeDomain1.Service.UnitTests.csproj" />
    <Project Path="src/Services/SomeDomain1/tests/SomeDomain1.Service/SomeDomain1.Service.IntegrationTests.csproj" />
  </Folder>
  <Folder Name="/Services/SomeDomain2/">
    <File Path="src/Services/SomeDomain2/SomeDomain2.slnx" />
    <File Path="src/Services/SomeDomain2/Directory.Build.props" />
  </Folder>
  <Folder Name="/Services/SomeDomain2/ApplicationLayer/">
    <Project Path="src/Services/SomeDomain2/src/SomeDomain2.ApplicationLayer/SomeDomain2.ApplicationLayer.csproj" />
    <Project Path="src/Services/SomeDomain2/tests/SomeDomain2.ApplicationLayer/SomeDomain2.ApplicationLayer.UnitTests.csproj" />
  </Folder>
  <Folder Name="/Services/SomeDomain2/Infrastructure/">
    <Project Path="src/Services/SomeDomain2/src/SomeDomain2.Infrastructure/SomeDomain2.Infrastructure.csproj" />
    <Project Path="src/Services/SomeDomain2/tests/SomeDomain2.Infrastructure/SomeDomain2.Infrastructure.UnitTests.csproj" />
  </Folder>
  <Folder Name="/Services/SomeDomain2/Service/">
    <Project Path="src/Services/SomeDomain2/src/SomeDomain2.Service/SomeDomain2.Service.csproj" />
    <Project Path="src/Services/SomeDomain2/tests/SomeDomain2.Service/SomeDomain2.Service.UnitTests.csproj" />
    <Project Path="src/Services/SomeDomain2/tests/SomeDomain2.Service/SomeDomain2.Service.IntegrationTests.csproj" />
  </Folder>
</Solution>
after:
Solution.slnx
<Solution>
  <Folder Name="/Solution Items/">
    <File Path=".gitignore" />
    <File Path="Directory.Build.props" />
    <File Path="Directory.Packages.props" />
    <File Path="README.md" />
  </Folder>
  <Folder Name="/Services/">
    <File Path="src/Services/Directory.Build.props" />
    <Folder Name="SomeDomain1/">
      <File Path="src/Services/SomeDomain1/SomeDomain1.slnx" />
      <File Path="src/Services/SomeDomain1/Directory.Build.props" />
      <Folder Name="ApplicationLayer/">
        <Project Path="src/Services/SomeDomain1/src/SomeDomain1.ApplicationLayer/SomeDomain1.ApplicationLayer.csproj" />
        <Project Path="src/Services/SomeDomain1/tests/SomeDomain1.ApplicationLayer.UnitTests/SomeDomain1.ApplicationLayer.UnitTests.csproj" />
      </Folder>
      <Folder Name="Infrastructure/">
        <Project Path="src/Services/SomeDomain1/src/SomeDomain1.Infrastructure/SomeDomain1.Infrastructure.csproj" />
        <Project Path="src/Services/SomeDomain1/tests/SomeDomain1.Infrastructure.UnitTests/SomeDomain1.Infrastructure.UnitTests.csproj" />
      </Folder>
      <Folder Name="Service/">
        <Project Path="src/Services/SomeDomain1/src/SomeDomain1.Service/SomeDomain1.Service.csproj" />
        <Project Path="src/Services/SomeDomain1/tests/SomeDomain1.Service.UnitTests/SomeDomain1.Service.UnitTests.csproj" />
        <Project Path="src/Services/SomeDomain1/tests/SomeDomain1.Service.IntegrationTests/SomeDomain1.Service.IntegrationTests.csproj" />
      </Folder>
    </Folder>
    <Folder Name="SomeDomain2/">
      <File Path="src/Services/SomeDomain2/SomeDomain2.slnx" />
      <File Path="src/Services/SomeDomain2/Directory.Build.props" />
      <Folder Name="ApplicationLayer/">
        <Project Path="src/Services/SomeDomain2/src/SomeDomain2.ApplicationLayer/SomeDomain2.ApplicationLayer.csproj" />
        <Project Path="src/Services/SomeDomain2/tests/SomeDomain2.ApplicationLayer.UnitTests/SomeDomain2.ApplicationLayer.UnitTests.csproj" />
      </Folder>
      <Folder Name="Infrastructure/">
        <Project Path="src/Services/SomeDomain2/src/SomeDomain2.Infrastructure/SomeDomain2.Infrastructure.csproj" />
        <Project Path="src/Services/SomeDomain2/tests/SomeDomain2.Infrastructure.UnitTests/SomeDomain2.Infrastructure.UnitTests.csproj" />
      </Folder>
      <Folder Name="Service/">
        <Project Path="src/Services/SomeDomain2/src/SomeDomain2.Service/SomeDomain2.Service.csproj" />
        <Project Path="src/Services/SomeDomain2/tests/SomeDomain2.Service.UnitTests/SomeDomain2.Service.UnitTests.csproj" />
        <Project Path="src/Services/SomeDomain2/tests/SomeDomain2.Service.IntegrationTests/SomeDomain2.Service.IntegrationTests.csproj" />
      </Folder>
    </Folder>
  </Folder>
</Solution>

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing how the repository parses and writes .slnx Folder elements, including the existing handling of File, Project, and Properties children. Implement nested folders with child names relative to their parent, then verify that the before-and-after examples round-trip while preserving the intended solution structure.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.