From 86ab68f4bb4f6d0c835bd3bfecb2e6c377780e93 Mon Sep 17 00:00:00 2001 From: srgif Date: Fri, 25 Jul 2025 09:31:32 -0700 Subject: [PATCH 1/4] Add async methods for C# source code retrieval Introduce `FindCSharpSourceCodeAsync` methods in `IVsProjectActions`, `IVsProjectFolderActions`, `VsProject`, and `VsProjectFolder` for searching C# source code files with customizable criteria. Add new classes `CsSearchContainer` and `CsSourceSearchCriteria` to model search results and criteria. Update using directives for integration. --- .../Models/CSharp/CsSearchContainer.cs | 99 +++++++++++++++++++ .../Models/CSharp/CsSourceSearchCriteria.cs | 59 +++++++++++ .../Models/ProjectSystem/IVsProjectActions.cs | 17 ++++ .../ProjectSystem/IVsProjectFolderActions.cs | 17 ++++ .../Models/ProjectSystem/VsProject.cs | 16 +++ .../Models/ProjectSystem/VsProjectFolder.cs | 16 +++ 6 files changed, 224 insertions(+) create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSourceSearchCriteria.cs diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs new file mode 100644 index 0000000..528c1e3 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text; + +namespace CodeFactory.WinVs.Models.CSharp +{ + /// + /// Data model that represents a summary of a C# container (class, interface, structure, etc.) for search results. + /// + public class CsSearchContainer + { + /// + /// The namespace the C# cntainer is defined in. + /// + public string Namespace { get; init; } + + /// + /// Gets the name of the container associated with the current instance. + /// + public string Name { get; init; } + + /// + /// The security scope of the container represented by this instance. + /// + CsSecurity Security { get; init; } = CsSecurity.Unknown; + + /// + /// Gets the type of the container represented by this instance. + /// + public CsContainerType ContainerType { get; init; } = CsContainerType.Unknown; + + /// + /// Flag that determines if this container has a generic type definition. + /// + public bool IsGenericContainer { get; init; } = false; + + /// + /// List of the generic parameters defined for the container. + /// + public IReadOnlyList GenericParameters { get; init; } = ImmutableList.Empty; + + /// + /// Flag that determines if the container has strong types defined in its generic parameters. + /// + public bool HasStrongTypesInGenerics { get; init; } = false; + + /// + /// List of the generic types defined for the container. + /// + public IReadOnlyList GenericTypes { get; init; } = ImmutableList.Empty; + + /// + /// Flag that determines if the container has a base class defined. + /// + public bool HasBaseClass { get; init; } = false; + + /// + /// Flag that determines if the container inherits from any interfaces. + /// + public bool HasInheritedInterfaces { get; init; } = false; + + /// + /// Flag that determines if the container has any attributes defined. + /// + public bool HasAttributes { get; init; } = false; + + /// + /// List of the attributes defined for the container. + /// + public IReadOnlyList Attributes { get; init; } = ImmutableList.Empty; + + /// + /// Flag that determines if the container has any fields defined. + /// + public bool HasFields { get; init; } = false; + + /// + /// Flag that determines if the container has any properties defined. + /// + public bool HasProperties { get; init; } = false; + + /// + /// Flag that determines if the container has any methods defined. + /// + public bool HasMethods { get; init; } = false; + + /// + /// Flag that determines if the container has any events defined. + /// + public bool HasEvents { get; init; } = false; + + /// + /// Flag that determines if the container has any constructors defined. + /// + public bool HasConstructors { get; init; } = false; + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSourceSearchCriteria.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSourceSearchCriteria.cs new file mode 100644 index 0000000..5547045 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSourceSearchCriteria.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Models.CSharp +{ + /// + /// Represents a set of search criteria for locating specific elements within a c# source code file. + /// + /// This class provides a collection of customizable search predicates that can be used to filter + /// and locate various elements within a source code container, such as methods, properties, fields, events, + /// constructors, inherited interfaces, and base classes. Each predicate allows the caller to define specific + /// conditions for the search, enabling flexible and precise queries. + public class CsSourceSearchCriteria + { + + /// + /// Stores the search criteria for searching for a specific container in the source code. + /// + public Func ContainerSearch { get; init; } = null; + + /// + /// Stores the search criteria for searching for a specific interface in the container. + /// + public Func, bool> InheritedInterfacesSearch { get; init; } = null; + + /// + /// Stores the search criteria for searching methods in the container. + /// + public Func, bool> MethodsSearch { get; init; } = null; + + /// + /// Stores the search criteria for searching properties in the container. + /// + public Func, bool> PropertiesSearch { get; init; } = null; + + /// + /// Stores the search criteria for searching fields in the container. + /// + public Func, bool> FieldsSearch { get; init; } = null; + + /// + /// Stores the search criteria for searching events in the container. + /// + public Func, bool> EventsSearch { get; init; } = null; + + /// + /// Stores the search criteria for constructors in the container. + /// + public Func, bool> ConstructorsSearch { get; init; } = null; + + /// + /// Stores the search criteria for searching the base class of the container. + /// + public Func BaseSearch { get; init; } = null; + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectActions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectActions.cs index 9993ce0..e0b9a02 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectActions.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectActions.cs @@ -3,6 +3,7 @@ //* Copyright (c) 2020-2023 CodeFactory, LLC //***************************************************************************** +using CodeFactory.WinVs.Models.CSharp; using System.Collections.Generic; using System.Threading.Tasks; @@ -68,5 +69,21 @@ public interface IVsProjectActions /// Readonly list of the referenced projects or an empty list if there is no referenced projects. Task> GetReferencedProjects(VsProject source); + /// + /// Asynchronously retrieves a collection of source code files from the specified Visual Studio project that + /// match the given search criteria. + /// + /// This method performs an asynchronous search within the provided project and applies + /// the specified search criteria to identify matching source code files. Use the parameter to exclude specific folders from the search if needed. + /// The Visual Studio project to search for source code files. + /// The criteria used to filter the source code files to be retrieved. + /// Flag that determines if sub folders from this location will be searched. Default value is true. + /// An optional collection of folder paths to exclude from the search. If , no folders are + /// excluded. When setting the folder paths just include the folder name. If you are going multiple folders deep use a forward slash as the folder seperator. + /// A task that represents the asynchronous operation. The task result contains a read-only list of objects that match the specified search criteria. + Task> FindCSharpSourceCodeAsync(VsProject source, CsSourceSearchCriteria searchCriteria, bool searchSubFolders = true, IEnumerable IgnoreFolderPaths = null); + } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectFolderActions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectFolderActions.cs index 9ba1b09..aad54ee 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectFolderActions.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectFolderActions.cs @@ -3,6 +3,7 @@ //* Copyright (c) 2020-2023 CodeFactory, LLC //***************************************************************************** +using CodeFactory.WinVs.Models.CSharp; using System.Collections.Generic; using System.Threading.Tasks; @@ -74,5 +75,21 @@ public interface IVsProjectFolderActions /// The project folder model to get the namespace for. /// The fully qualified namespace if the project is a c# project that supports this project folder. Otherwise null will be returned. Task GetCSharpNamespaceAsync(VsProjectFolder source); + + /// + /// Asynchronously retrieves a collection of source code files from the specified Visual Studio project folder that + /// match the given search criteria. + /// + /// This method performs an asynchronous search within the provided project and applies + /// the specified search criteria to identify matching source code files. Use the parameter to exclude specific folders from the search if needed. + /// The Visual Studio project folder to search for source code files. + /// The criteria used to filter the source code files to be retrieved. + /// Flag that determines if sub folders from this location will be searched. Default value is true. + /// An optional collection of folder paths to exclude from the search. If , no folders are + /// excluded. When setting the folder paths just include the folder name. If you are going multiple folders deep use a forward slash as the folder seperator. + /// A task that represents the asynchronous operation. The task result contains a read-only list of objects that match the specified search criteria. + Task> FindCSharpSourceCodeAsync(VsProjectFolder source, CsSourceSearchCriteria searchCriteria, bool searchSubFolders = true, IEnumerable IgnoreFolderPaths = null); } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProject.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProject.cs index 15d1975..bdcd925 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProject.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProject.cs @@ -3,6 +3,7 @@ //* Copyright (c) 2020-2023 CodeFactory, LLC //***************************************************************************** +using CodeFactory.WinVs.Models.CSharp; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -152,5 +153,20 @@ public async Task> GetReferencedProjects() return projects.Any() ? projects.ToImmutableList() : ImmutableList.Empty; } + + /// + /// Asynchronously retrieves a collection of source code files from the specified Visual Studio project that + /// match the given search criteria. + /// + /// This method performs an asynchronous search within the provided project and applies + /// the specified search criteria to identify matching source code files. Use the parameter to exclude specific folders from the search if needed. + /// The criteria used to filter the source code files to be retrieved. + /// Flag that determines if sub folders from this location will be searched. Default value is true. + /// An optional collection of folder paths to exclude from the search. If , no folders are + /// excluded. When setting the folder paths just include the folder name. If you are going multiple folders deep use a forward slash as the folder seperator. + /// A task that represents the asynchronous operation. The task result contains a read-only list of objects that match the specified search criteria. + public abstract Task> FindCSharpSourceCodeAsync(CsSourceSearchCriteria searchCriteria, bool searchSubFolders = true, IEnumerable IgnoreFolderPaths = null); } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolder.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolder.cs index 3dbb265..a54cfa0 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolder.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolder.cs @@ -3,6 +3,7 @@ //* Copyright (c) 2020-2023 CodeFactory, LLC //***************************************************************************** +using CodeFactory.WinVs.Models.CSharp; using System.Collections.Generic; using System.Threading.Tasks; @@ -110,5 +111,20 @@ protected VsProjectFolder(bool isLoaded, bool hasErrors, /// /// The fully qualified namespace if the project is a c# project that supports this project folder. Otherwise null will be returned. public abstract Task GetCSharpNamespaceAsync(); + + /// + /// Asynchronously retrieves a collection of source code files from the specified Visual Studio project folder that + /// match the given search criteria. + /// + /// This method performs an asynchronous search within the provided project folder and applies + /// the specified search criteria to identify matching source code files. Use the parameter to exclude specific folders from the search if needed. + /// The criteria used to filter the source code files to be retrieved. + /// Flag that determines if sub folders from this location will be searched. Default value is true. + /// An optional collection of folder paths to exclude from the search. If , no folders are + /// excluded. When setting the folder paths just include the folder name. If you are going multiple folders deep use a forward slash as the folder seperator. + /// A task that represents the asynchronous operation. The task result contains a read-only list of objects that match the specified search criteria. + public abstract Task> FindCSharpSourceCodeAsync(CsSourceSearchCriteria searchCriteria, bool searchSubFolders = true, IEnumerable IgnoreFolderPaths = null); } } From 411810822e04ffec329d5a07d0aa1d25f731a42c Mon Sep 17 00:00:00 2001 From: srgif Date: Fri, 25 Jul 2025 21:05:08 -0700 Subject: [PATCH 2/4] Update version to 2.25206.0.1-PreRelease - Bump version in `.nuspec`, `AssemblyInfo.cs`, and `.csproj` files. - Update release notes with recompilation instructions. - Refresh dependencies to match the new version. - Modify `SdkSupport.cs` to reflect updated SDK version constants. - Add `FilePath` property to `CsSearchContainer` class. - Remove boolean properties from `CsSearchContainer` for simplification. - Introduce new asynchronous methods for loading C# source files. - Refactor methods in `VsProjectExtensions.cs` for improved readability. - Clean up `using` directives and comments in `VsProjectFolderExtensions.cs`. --- .../CodeFactoryWinVsSDK.nuspec | 10 +-- .../Properties/AssemblyInfo.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- .../CodeFactory.WinVs.Wpf/WinVsWpf.nuspec | 8 +- .../CodeFactory.WinVs.csproj | 6 +- .../CodeFactory.WinVs/Loader/SdkSupport.cs | 6 +- .../Models/CSharp/CsSearchContainer.cs | 31 ++------ .../Models/ProjectSystem/IVsProjectActions.cs | 11 +++ .../ProjectSystem/IVsProjectFolderActions.cs | 11 +++ .../Models/ProjectSystem/IVsSourceActions.cs | 27 +++++++ .../Models/ProjectSystem/VsProject.cs | 19 +++++ .../ProjectSystem/VsProjectExtensions.cs | 67 +++++++++++----- .../Models/ProjectSystem/VsProjectFolder.cs | 19 +++++ .../VsProjectFolderExtensions.cs | 79 ++++++++++++++++--- .../CodeFactory/CodeFactory.csproj | 6 +- 15 files changed, 229 insertions(+), 75 deletions(-) diff --git a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec index f294ff4..90c1137 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec +++ b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec @@ -2,7 +2,7 @@ CodeFactory.WinVs.SDK - 2.25191.0.1-PreRelease + 2.25206.0.1-PreRelease CodeFactory Software Development Kit for Visual Studio - Windows CodeFactory, LLC. CodeFactory, LLC. @@ -10,7 +10,7 @@ true Software development kit for building CodeFactory automation in Visual Studio - Windows. - Release Updates for 2.25191.0.1 + Release Updates for 2.25206.0.1 Recompile Release: When you update your automation to this version of the SDK. @@ -40,9 +40,9 @@ Copyright © 2025 CodeFactory, LLC. Factory Automation - - - + + + CFLogo128.png diff --git a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs index 9e2a053..dd33a72 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs @@ -33,4 +33,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.25191.0.1")] +[assembly: AssemblyFileVersion("2.25206.0.1")] diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs index 11cbbde..02136d1 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs @@ -33,4 +33,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.25191.0.1")] +[assembly: AssemblyFileVersion("2.25206.0.1")] diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec index 50aa81d..a5a19e0 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec @@ -2,7 +2,7 @@ CodeFactory.WinVs.Wpf - 2.25191.0.1-PreRelease + 2.25206.0.1-PreRelease CodeFactory User Interface WPF for Visual Studio - Windows CodeFactory, LLC. CodeFactory, LLC. @@ -10,7 +10,7 @@ true Library that provides custom dialog screens hosted in Visual Studio for Windows, hosted for CodeFactory automation. - Release Updates for 2.25191.0.1 + Release Updates for 2.25206.0.1 Recompile Release: When you update your automation to this version of the SDK. @@ -19,8 +19,8 @@ Copyright © 2025 CodeFactory, LLC. Factory Automation - - + + CFLogo128.png diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj b/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj index 45893ee..8e89cfa 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj @@ -6,7 +6,7 @@ True CFSigner.snk True - 2.25191.0.1-PreRelease + 2.25206.0.1-PreRelease CodeFactory, LLC. CodeFactory, LLC. CodeFactory Base Library @@ -17,10 +17,10 @@ False CodeFactory API for Visual Studio - Windows 2.0.0.0 - 2.25191.0.1 + 2.25206.0.1 CFLogo128.png - Release Updates for 2.25191.0.1 + Release Updates for 2.25206.0.1 Recompile Release: When you update your automation to this version of the SDK. diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs index 197d904..5aedba4 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs @@ -18,17 +18,17 @@ public static class SdkSupport /// /// The minimum version of the SDK that can be loaded and used. /// - public const string MinVersion = "2.25191.0.1"; + public const string MinVersion = "2.25206.0.1"; /// /// The maximum version of the SDK that can be loaded and used. /// - public const string MaxVersion = "2.25191.0.1"; + public const string MaxVersion = "2.25206.0.1"; /// /// The target version of the NuGet package this SDK is deployed from. /// - public const string NuGetSdkVersion = "2.25191.0.1-PreRelease"; + public const string NuGetSdkVersion = "2.25206.0.1-PreRelease"; /// /// The name of the assembly type for the CodeFactory SDK version attribute. diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs index 528c1e3..7b272e6 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs @@ -10,6 +10,12 @@ namespace CodeFactory.WinVs.Models.CSharp /// public class CsSearchContainer { + + /// + /// The file path of the C# container represented by this instance. + /// + public string FilePath { get; init; } = null; + /// /// The namespace the C# cntainer is defined in. /// @@ -70,30 +76,5 @@ public class CsSearchContainer /// public IReadOnlyList Attributes { get; init; } = ImmutableList.Empty; - /// - /// Flag that determines if the container has any fields defined. - /// - public bool HasFields { get; init; } = false; - - /// - /// Flag that determines if the container has any properties defined. - /// - public bool HasProperties { get; init; } = false; - - /// - /// Flag that determines if the container has any methods defined. - /// - public bool HasMethods { get; init; } = false; - - /// - /// Flag that determines if the container has any events defined. - /// - public bool HasEvents { get; init; } = false; - - /// - /// Flag that determines if the container has any constructors defined. - /// - public bool HasConstructors { get; init; } = false; - } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectActions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectActions.cs index e0b9a02..e134e26 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectActions.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectActions.cs @@ -85,5 +85,16 @@ public interface IVsProjectActions /// cref="CsSource"/> objects that match the specified search criteria. Task> FindCSharpSourceCodeAsync(VsProject source, CsSourceSearchCriteria searchCriteria, bool searchSubFolders = true, IEnumerable IgnoreFolderPaths = null); + + /// + /// Asynchronously loads a object from the specified C# source file within a Visual + /// Studio project. + /// + /// The Visual Studio project that contains the C# source file. + /// The C# source file to load. + /// A task that represents the asynchronous operation. The task result contains the loaded object. + Task LoadFromCsSourceAsync(VsProject source,CsSource csSource); + } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectFolderActions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectFolderActions.cs index aad54ee..e4a015e 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectFolderActions.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsProjectFolderActions.cs @@ -91,5 +91,16 @@ public interface IVsProjectFolderActions /// A task that represents the asynchronous operation. The task result contains a read-only list of objects that match the specified search criteria. Task> FindCSharpSourceCodeAsync(VsProjectFolder source, CsSourceSearchCriteria searchCriteria, bool searchSubFolders = true, IEnumerable IgnoreFolderPaths = null); + + + /// + /// Asynchronously loads a object from the specified C# source file within a Visual + /// Studio project folder. + /// + /// The Visual Studio project folder that contains the C# source file. + /// The C# source file to load. + /// A task that represents the asynchronous operation. The task result contains the loaded object. + Task LoadFromCsSourceAsync(VsProjectFolder source, CsSource csSource); } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsSourceActions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsSourceActions.cs index c12e474..1d33e3c 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsSourceActions.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/IVsSourceActions.cs @@ -22,5 +22,32 @@ public interface IVsSourceActions /// Loaded document model. /// Exception that occurs while loading the document. Task LoadDocumentFromSourceAsync(ICsSource source); + + /// + /// Asynchronously loads a C# source file from the specified source. + /// + /// The source from which the C# file will be loaded. Cannot be null. + /// A task that represents the asynchronous operation. The task result contains a + /// object representing the loaded C# source file. + Task LoadCSharpSourceFromSourceAsync(CsSource source); + + + /// + /// Asynchronously loads a C# source file from the specified container. + /// + /// The container from which the C# source file will be loaded. This parameter cannot be null. + /// A task that represents the asynchronous operation. The task result contains the loaded object. + Task LoadCSharpSourceFromContainerAsync(CsContainer source); + + /// + /// Asynchronously loads a C# source file from the specified container. + /// + /// This method retrieves and parses a C# source file from the provided container. Ensure + /// that the container contains a valid and accessible C# source file before calling this method. + /// The container from which the C# source file will be loaded. Must not be . + /// A task that represents the asynchronous operation. The task result contains the loaded object. + Task LoadCsSourceFromContainerAsync(CsContainer source); } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProject.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProject.cs index bdcd925..e596ca1 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProject.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProject.cs @@ -168,5 +168,24 @@ public async Task> GetReferencedProjects() /// A task that represents the asynchronous operation. The task result contains a read-only list of objects that match the specified search criteria. public abstract Task> FindCSharpSourceCodeAsync(CsSourceSearchCriteria searchCriteria, bool searchSubFolders = true, IEnumerable IgnoreFolderPaths = null); + + + /// + /// Asynchronously loads a object from the specified C# source file within a Visual + /// Studio project. + /// + /// The C# source file to load. + /// A task that represents the asynchronous operation. The task result contains the loaded object. + public abstract Task LoadFromCsSourceAsync(CsSource csSource); + + + /// + /// Asynchronously loads a C# source file from the specified container. + /// + /// The container from which the C# source file will be loaded. This parameter cannot be null. + /// A task that represents the asynchronous operation. The task result contains the loaded object. + public abstract Task LoadCSharpSourceFromContainerAsync(CsContainer source); } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectExtensions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectExtensions.cs index 38c03ef..35ee342 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectExtensions.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectExtensions.cs @@ -27,14 +27,23 @@ public static async Task FindCSharpSourceByClassNameAsync(this V if (string.IsNullOrEmpty(className)) return null; - var children = await source.GetChildrenAsync(searchAllFolders, true); + //var children = await source.GetChildrenAsync(searchAllFolders, true); + + //var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) + // .Cast(); + + //var result = sourceCode.FirstOrDefault(s => s.SourceCode.Classes.Any(c => c.Name == className)); + + var searchCriteria = new CsSourceSearchCriteria + { + ContainerSearch = c => (c.Name == className) & (c.ContainerType == CsContainerType.Class) + }; - var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) - .Cast(); + var classSources = await source.FindCSharpSourceCodeAsync(searchCriteria, searchAllFolders); - var result = sourceCode.FirstOrDefault(s => s.SourceCode.Classes.Any(c => c.Name == className)); + var classSource = classSources.FirstOrDefault(); - return result; + return classSource != null ? await source.LoadFromCsSourceAsync(classSource) : null; } /// @@ -51,17 +60,27 @@ public static async Task FindCSharpSourceByInterfaceNameAsync(th if (string.IsNullOrEmpty(name)) return null; - var children = await source.GetChildrenAsync(searchAllFolders, true); + // var children = await source.GetChildrenAsync(searchAllFolders, true); + + // var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) + // .Cast(); - var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) - .Cast(); + //if(sourceCode == null) return null; + //if(!sourceCode.Any()) return null; - if(sourceCode == null) return null; - if(!sourceCode.Any()) return null; + // var result = sourceCode.FirstOrDefault(s => s.SourceCode.Interfaces.Any(c => c.Name == name)); + + var searchCriteria = new CsSourceSearchCriteria + { + ContainerSearch = c => (c.Name == name) & (c.ContainerType == CsContainerType.Interface) + }; - var result = sourceCode.FirstOrDefault(s => s.SourceCode.Interfaces.Any(c => c.Name == name)); + var interfaceSources = await source.FindCSharpSourceCodeAsync(searchCriteria, searchAllFolders); + + var interfaceSource = interfaceSources.FirstOrDefault(); + + return interfaceSource != null ? await source.LoadFromCsSourceAsync(interfaceSource) : null; - return result; } /// @@ -78,17 +97,27 @@ public static async Task FindCSharpSourceByFileNameAsync(this Vs if (string.IsNullOrEmpty(fileName)) return null; - var children = await source.GetChildrenAsync(searchAllFolders, true); + //var children = await source.GetChildrenAsync(searchAllFolders, true); + + //var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) + // .Cast(); + + //if (sourceCode == null) return null; + //if (!sourceCode.Any()) return null; + + //var result = sourceCode.FirstOrDefault(s => Path.GetFileName(s.SourceCode.SourceDocument) == fileName); + + var searchCriteria = new CsSourceSearchCriteria + { + ContainerSearch = f => f.FilePath != null ? Path.GetFileName(f.FilePath) == fileName : false + }; - var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) - .Cast(); + var fileSources = await source.FindCSharpSourceCodeAsync(searchCriteria, searchAllFolders); - if (sourceCode == null) return null; - if (!sourceCode.Any()) return null; + var fileSource = fileSources.FirstOrDefault(); - var result = sourceCode.FirstOrDefault(s => Path.GetFileName(s.SourceCode.SourceDocument) == fileName); + return fileSource != null ? await source.LoadFromCsSourceAsync(fileSource) : null; - return result; } /// diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolder.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolder.cs index a54cfa0..3fe6efe 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolder.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolder.cs @@ -126,5 +126,24 @@ protected VsProjectFolder(bool isLoaded, bool hasErrors, /// A task that represents the asynchronous operation. The task result contains a read-only list of objects that match the specified search criteria. public abstract Task> FindCSharpSourceCodeAsync(CsSourceSearchCriteria searchCriteria, bool searchSubFolders = true, IEnumerable IgnoreFolderPaths = null); + + + /// + /// Asynchronously loads a object from the specified C# source file within a Visual + /// Studio project folder. + /// + /// The C# source file to load. + /// A task that represents the asynchronous operation. The task result contains the loaded object. + public abstract Task LoadFromCsSourceAsync(CsSource csSource); + + + /// + /// Asynchronously loads a C# source file from the specified container. + /// + /// The container from which the C# source file will be loaded. This parameter cannot be null. + /// A task that represents the asynchronous operation. The task result contains the loaded object. + public abstract Task LoadCSharpSourceFromContainerAsync(CsContainer source); } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolderExtensions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolderExtensions.cs index 822038d..1b10ccb 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolderExtensions.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/ProjectSystem/VsProjectFolderExtensions.cs @@ -1,5 +1,7 @@ -using System; +using CodeFactory.WinVs.Models.CSharp; +using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -25,14 +27,23 @@ public static async Task FindCSharpSourceByClassNameAsync(this V if (string.IsNullOrEmpty(className)) return null; - var children = await source.GetChildrenAsync(searchSubFolders, true); + //var children = await source.GetChildrenAsync(searchSubFolders, true); - var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) - .Cast(); + //var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) + // .Cast(); - var result = sourceCode.FirstOrDefault(s => s.SourceCode.Classes.Any(c => c.Name == className)); + //var result = sourceCode.FirstOrDefault(s => s.SourceCode.Classes.Any(c => c.Name == className)); - return result; + var searchCriteria = new CsSourceSearchCriteria + { + ContainerSearch = c => (c.Name == className) & (c.ContainerType == CsContainerType.Class) + }; + + var classSources = await source.FindCSharpSourceCodeAsync(searchCriteria, searchSubFolders); + + var classSource = classSources.FirstOrDefault(); + + return classSource != null ? await source.LoadFromCsSourceAsync(classSource) : null; } /// @@ -49,14 +60,60 @@ public static async Task FindCSharpSourceByInterfaceNameAsync(th if (string.IsNullOrEmpty(name)) return null; - var children = await source.GetChildrenAsync(searchSubFolders, true); + //var children = await source.GetChildrenAsync(searchSubFolders, true); + + //var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) + // .Cast(); + + //var result = sourceCode.FirstOrDefault(s => s.SourceCode.Interfaces.Any(c => c.Name == name)); + + var searchCriteria = new CsSourceSearchCriteria + { + ContainerSearch = c => (c.Name == name) & (c.ContainerType == CsContainerType.Interface) + }; + + var interfaceSources = await source.FindCSharpSourceCodeAsync(searchCriteria, searchSubFolders); + + var interfaceSource = interfaceSources.FirstOrDefault(); + + return interfaceSource != null ? await source.LoadFromCsSourceAsync(interfaceSource) : null; + } + + /// + /// Locates a target model by the filename of the source code file. + /// + /// The project to search the model for. + /// The name of the source code file. + /// optional flag that determines if all folders under the project should be searched. + /// The source code model for the target code file found. + public static async Task FindCSharpSourceByFileNameAsync(this VsProjectFolder source, string fileName, bool searchAllFolders = true) + { + //Bounds checking + if (source == null) return null; + + if (string.IsNullOrEmpty(fileName)) return null; + + //var children = await source.GetChildrenAsync(searchAllFolders, true); + + //var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) + // .Cast(); + + //if (sourceCode == null) return null; + //if (!sourceCode.Any()) return null; + + //var result = sourceCode.FirstOrDefault(s => Path.GetFileName(s.SourceCode.SourceDocument) == fileName); + + var searchCriteria = new CsSourceSearchCriteria + { + ContainerSearch = f => f.FilePath != null ? Path.GetFileName(f.FilePath) == fileName : false + }; + + var fileSources = await source.FindCSharpSourceCodeAsync(searchCriteria, searchAllFolders); - var sourceCode = children.Where(m => m.ModelType == VisualStudioModelType.CSharpSource) - .Cast(); + var fileSource = fileSources.FirstOrDefault(); - var result = sourceCode.FirstOrDefault(s => s.SourceCode.Interfaces.Any(c => c.Name == name)); + return fileSource != null ? await source.LoadFromCsSourceAsync(fileSource) : null; - return result; } } } diff --git a/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj b/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj index f90df1a..242e28e 100644 --- a/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj +++ b/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj @@ -6,7 +6,7 @@ True CFSigner.snk True - 2.25191.0.1-PreRelease + 2.25206.0.1-PreRelease CodeFactory, LLC. CodeFactory, LLC. CodeFactory Base Library @@ -17,11 +17,11 @@ False CodeFactory Base Libraries 2.0.0.0 - 2.25191.0.1 + 2.25206.0.1 CFLogo128.png git - Release Updates for 2.25191.0.1 + Release Updates for 2.25206.0.1 Recompile Release: When you update your automation to this version of the SDK. From 8befc385a74dc62c3bcc5933f63ff7b2d9ee8cf4 Mon Sep 17 00:00:00 2001 From: srgif Date: Sat, 2 Aug 2025 14:54:45 -0700 Subject: [PATCH 3/4] Update SDK version to 2.25214.0.1-PreRelease - Bump version numbers in `.nuspec` and `.csproj` files. - Modify `AssemblyFileVersion` in `AssemblyInfo.cs`. - Update SDK version constants in `SdkSupport.cs`. - Enhance documentation comments across multiple classes. - Add `DirectInheritedInterfaces` property for better inheritance tracking. - Update constructor parameters to include `directInheritedInterfaces`. - Refine `CsSearchContainer` to encapsulate additional metadata. - Improve overall documentation clarity and structure. --- .../CodeFactoryWinVsSDK.nuspec | 10 +- .../Properties/AssemblyInfo.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- .../CodeFactory.WinVs.Wpf/WinVsWpf.nuspec | 8 +- .../CodeFactory.WinVs.csproj | 6 +- .../CodeFactory.WinVs/Loader/SdkSupport.cs | 6 +- .../Models/CSharp/CsClass.cs | 70 ++++++------ .../Models/CSharp/CsContainer.cs | 69 +++++++----- .../CSharp/CsContainerWithNestedContainers.cs | 69 ++++++------ .../Models/CSharp/CsInterface.cs | 64 ++++++----- .../Models/CSharp/CsRecord.cs | 66 ++++++------ .../Models/CSharp/CsRecordStructure.cs | 54 +++++----- .../Models/CSharp/CsSearchContainer.cs | 101 +++++++++++++++--- .../Models/CSharp/CsStructure.cs | 60 ++++++----- .../Models/CSharp/ICsContainer.cs | 5 + .../CodeFactory/CodeFactory.csproj | 6 +- 16 files changed, 359 insertions(+), 239 deletions(-) diff --git a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec index 90c1137..3d1848b 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec +++ b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec @@ -2,7 +2,7 @@ CodeFactory.WinVs.SDK - 2.25206.0.1-PreRelease + 2.25214.0.1-PreRelease CodeFactory Software Development Kit for Visual Studio - Windows CodeFactory, LLC. CodeFactory, LLC. @@ -10,7 +10,7 @@ true Software development kit for building CodeFactory automation in Visual Studio - Windows. - Release Updates for 2.25206.0.1 + Release Updates for 2.25214.0.1 Recompile Release: When you update your automation to this version of the SDK. @@ -40,9 +40,9 @@ Copyright © 2025 CodeFactory, LLC. Factory Automation - - - + + + CFLogo128.png diff --git a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs index dd33a72..9af97e4 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs @@ -33,4 +33,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.25206.0.1")] +[assembly: AssemblyFileVersion("2.25214.0.1")] diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs index 02136d1..26a4726 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs @@ -33,4 +33,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.25206.0.1")] +[assembly: AssemblyFileVersion("2.25214.0.1")] diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec index a5a19e0..53ef8bc 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec @@ -2,7 +2,7 @@ CodeFactory.WinVs.Wpf - 2.25206.0.1-PreRelease + 2.25214.0.1-PreRelease CodeFactory User Interface WPF for Visual Studio - Windows CodeFactory, LLC. CodeFactory, LLC. @@ -10,7 +10,7 @@ true Library that provides custom dialog screens hosted in Visual Studio for Windows, hosted for CodeFactory automation. - Release Updates for 2.25206.0.1 + Release Updates for 2.25214.0.1 Recompile Release: When you update your automation to this version of the SDK. @@ -19,8 +19,8 @@ Copyright © 2025 CodeFactory, LLC. Factory Automation - - + + CFLogo128.png diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj b/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj index 8e89cfa..b428b62 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj @@ -6,7 +6,7 @@ True CFSigner.snk True - 2.25206.0.1-PreRelease + 2.25214.0.1-PreRelease CodeFactory, LLC. CodeFactory, LLC. CodeFactory Base Library @@ -17,10 +17,10 @@ False CodeFactory API for Visual Studio - Windows 2.0.0.0 - 2.25206.0.1 + 2.25214.0.1 CFLogo128.png - Release Updates for 2.25206.0.1 + Release Updates for 2.25214.0.1 Recompile Release: When you update your automation to this version of the SDK. diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs index 5aedba4..ab76b29 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs @@ -18,17 +18,17 @@ public static class SdkSupport /// /// The minimum version of the SDK that can be loaded and used. /// - public const string MinVersion = "2.25206.0.1"; + public const string MinVersion = "2.25214.0.1"; /// /// The maximum version of the SDK that can be loaded and used. /// - public const string MaxVersion = "2.25206.0.1"; + public const string MaxVersion = "2.25214.0.1"; /// /// The target version of the NuGet package this SDK is deployed from. /// - public const string NuGetSdkVersion = "2.25206.0.1-PreRelease"; + public const string NuGetSdkVersion = "2.25214.0.1-PreRelease"; /// /// The name of the assembly type for the CodeFactory SDK version attribute. diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsClass.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsClass.cs index 3166413..a19e8d8 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsClass.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsClass.cs @@ -23,48 +23,52 @@ public abstract class CsClass:CsContainerWithNestedContainers,ICsClass #endregion /// - /// Constructor for the + /// Represents a C# class model, providing metadata and structural information about the class. /// - /// Flag that determines if the model was loaded. - /// Flag that determine if errors were found creating the model. - /// Flag that determines if the model was loaded from source code or from an existing library. - /// The target language the model was generated from. - /// The members assigned to this container. - /// Flag that determines if the container type is nested in another type definition. - /// Enumeration of the type of nesting the container is. - /// List of nested models assigned to this container. This is an optional parameter and can be null - /// The class model that is base class of this class. - /// The source document that was used to build this model. This is optional parameter and can be null. - /// Optional the lookup storage for models created during the compile or lookup of the model. - /// Optional the error that occurred while creating the model. - /// List of the attributes assigned to this model. - /// Flag that determines if the container is a generic definition. - /// Flag that determines if the generics use strong type definitions. - /// Generic parameters assigned to the container. - /// Target types for the generic parameters assigned to the container. - /// The source code file the model was generated from. - /// List of the fully qualified paths to the source code files this model is defined in. - /// Flag that determines if the model has XML documentation assigned to it. - /// The xml documentation assigned to the model. - /// The fully qualified model lookup path for this model. - /// The name of the model. - /// The namespace the container belongs to. - /// The fully qualified lookup path for the parent model to this one. - /// The security scope assigned to this model. - /// The interfaces that are inherited by this container. - /// Flag that determines if the model is static. - /// Flag that determines if the model is abstract. - /// Flag that determines if the model is sealed. + /// This class encapsulates details about a C# class, including its attributes, generic + /// parameters, inheritance hierarchy, members, and other metadata. It is primarily used to analyze and + /// represent the structure of a class in source code. + /// Indicates whether the class model has been successfully loaded. + /// Indicates whether the class model contains errors. + /// Indicates whether the class was loaded directly from source code. + /// The programming language of the source code (e.g., C#). + /// A read-only list of attributes applied to the class. + /// Indicates whether the class is a generic type. + /// Indicates whether the generic parameters of the class are strongly typed. + /// A read-only list of generic parameters defined by the class. + /// A read-only list of generic types used by the class. + /// The file path of the primary source file for the class. + /// A read-only list of source files associated with the class. + /// Indicates whether the class has associated XML documentation. + /// The XML documentation associated with the class, if available. + /// The lookup path used to identify the class within its namespace or hierarchy. + /// The name of the class. + /// The namespace to which the class belongs. + /// The hierarchical path of the parent container, if the class is nested. + /// The security level (accessibility) of the class (e.g., public, private). + /// A read-only list of all interfaces inherited by the class, including those inherited indirectly. + /// A read-only list of interfaces directly implemented by the class. + /// A read-only list of members (e.g., methods, properties, fields) defined in the class. + /// Indicates whether the class is nested within another type. + /// The type of nesting, if the class is nested. + /// Indicates whether the class is static. + /// Indicates whether the class is abstract. + /// Indicates whether the class is sealed. + /// The base class from which this class directly inherits, if any. + /// A read-only list of nested models (e.g., nested classes, interfaces) within the class. + /// The source document associated with the class, if available. + /// The model store containing additional metadata or related models for the class. + /// A read-only list of errors encountered while loading the class model, if any. protected CsClass(bool isLoaded, bool hasErrors, bool loadedFromSource, SourceCodeType language, IReadOnlyList attributes, bool isGeneric, bool hasStrongTypesInGenerics, IReadOnlyList genericParameters, IReadOnlyList genericTypes, string modelSourceFile, IReadOnlyList sourceFiles, bool hasDocumentation, string documentation, string lookupPath, string name, string ns, string parentPath, - CsSecurity security, IReadOnlyList inheritedInterfaces, IReadOnlyList members,bool isNested, CsNestedType nestedType, + CsSecurity security, IReadOnlyList inheritedInterfaces,IReadOnlyList directInheritedInterfaces, IReadOnlyList members,bool isNested, CsNestedType nestedType, bool isStatic, bool isAbstract, bool isSealed, CsClass baseClass,IReadOnlyList nestedModels, string sourceDocument = null, ModelStore modelStore = null, IReadOnlyList modelErrors = null) : base(isLoaded, hasErrors, loadedFromSource, language, CsModelType.Class, attributes, isGeneric, hasStrongTypesInGenerics, genericParameters, genericTypes, modelSourceFile, sourceFiles, hasDocumentation, - documentation, lookupPath, name, ns, parentPath, CsContainerType.Class, security, inheritedInterfaces, + documentation, lookupPath, name, ns, parentPath, CsContainerType.Class, security, inheritedInterfaces, directInheritedInterfaces, members,isNested,nestedType,nestedModels, sourceDocument, modelStore, modelErrors) { _isStatic = isStatic; diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsContainer.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsContainer.cs index ee2bdb2..dbcb713 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsContainer.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsContainer.cs @@ -34,44 +34,50 @@ public abstract class CsContainer:CsModel,ICsContainer private readonly CsContainerType _containerType; private readonly CsSecurity _security; private readonly IReadOnlyList _inheritedInterfaces; + private readonly IReadOnlyList _directInheritedInterfaces; private readonly IReadOnlyList _members; #endregion /// - /// Constructor for the - /// - /// Flag that determines if the model was loaded. - /// Flag that determine if errors were found creating the model. - /// Flag that determines if the model was loaded from source code or from an existing library. - /// The target language the model was generated from. - /// The type of code model created. - /// The members assigned to this container. - /// The source document that was used to build this model. This is optional parameter and can be null. - /// Optional the lookup storage for models created during the compile or lookup of the model. - /// Optional the error that occurred while creating the model. - /// List of the attributes assigned to this model. - /// Flag that determines if the container is a generic definition. - /// Flag that determines if the generics use strong type definitions. - /// Generic parameters assigned to the container. - /// Target types for the generic parameters assigned to the container. - /// The source file the model was loaded from. - /// List of the fully qualified paths to the source code files this model is defined in. - /// Flag that determines if the model has XML documentation assigned to it. - /// The xml documentation assigned to the model. - /// The fully qualified model lookup path for this model. - /// The name of the model. - /// The namespace the container belongs to. - /// The fully qualified lookup path for the parent model to this one. - /// The type of container this model represents. - /// The security scope assigned to this model. - /// The interfaces that are inherited by this container. + /// Initializes a new instance of the class, representing a container for code model + /// elements such as classes, interfaces, or structs. + /// + /// This constructor is typically used to initialize a container that represents a code + /// model element such as a class, interface, or struct. It provides detailed information about the container's + /// attributes, generic parameters, inheritance, and associated source files. + /// Indicates whether the container has been successfully loaded. + /// Indicates whether the container contains any errors. + /// Indicates whether the container was loaded from source code. + /// The programming language of the source code represented by the container. + /// The type of the model represented by the container. + /// A collection of attributes applied to the container. + /// Indicates whether the container is a generic type. + /// Indicates whether the generic parameters of the container are strongly typed. + /// A collection of generic parameters defined by the container. + /// A collection of generic types used by the container. + /// The file path of the source file where the container is defined. + /// A collection of source files associated with the container. + /// Indicates whether the container has associated documentation. + /// The documentation associated with the container, if available. + /// The lookup path used to identify the container within the model. + /// The name of the container. + /// The namespace to which the container belongs. + /// The path of the parent container, if applicable. + /// The type of the container (e.g., class, interface, struct). + /// The security level of the container (e.g., public, private, protected). + /// A collection of interfaces inherited by the container, including both direct and indirect inheritance. + /// A collection of interfaces directly inherited by the container. + /// A collection of members (e.g., methods, properties) defined within the container. + /// The source document associated with the container, if applicable. This parameter is optional. + /// The model store used to manage the container's associated models. This parameter is optional. + /// A collection of errors encountered during the loading of the container. This parameter is optional. protected CsContainer(bool isLoaded, bool hasErrors, bool loadedFromSource, SourceCodeType language, CsModelType modelType, IReadOnlyList attributes, bool isGeneric, bool hasStrongTypesInGenerics, IReadOnlyList genericParameters, IReadOnlyList genericTypes, string modelSourceFile, IReadOnlyList sourceFiles, bool hasDocumentation, string documentation, string lookupPath, string name, string ns, string parentPath, CsContainerType containerType, CsSecurity security, - IReadOnlyList inheritedInterfaces, IReadOnlyList members, + IReadOnlyList inheritedInterfaces, IReadOnlyList directInheritedInterfaces, IReadOnlyList members, string sourceDocument = null, ModelStore modelStore = null, IReadOnlyList modelErrors = null) : base(isLoaded, hasErrors, loadedFromSource, language, modelType, sourceDocument, modelStore, modelErrors) { @@ -91,6 +97,7 @@ protected CsContainer(bool isLoaded, bool hasErrors, bool loadedFromSource, Sour _containerType = containerType; _security = security; _inheritedInterfaces = inheritedInterfaces ?? ImmutableList.Empty; + _directInheritedInterfaces = directInheritedInterfaces ?? ImmutableList.Empty; _members = members ?? ImmutableList.Empty; } @@ -205,6 +212,11 @@ protected CsContainer(bool isLoaded, bool hasErrors, bool loadedFromSource, Sour /// public IReadOnlyList InheritedInterfaces => _inheritedInterfaces; + /// + /// List of the interfaces that are directly inherited by this container. This does not include interfaces that are inherited by base classes. Or interfaces that are inherited by other interfaces that this container inherits from. + /// + public IReadOnlyList DirectInheritedInterfaces => throw new NotImplementedException(); + /// /// List of the members that are implemented in this container. /// @@ -450,5 +462,6 @@ protected CsContainer(bool isLoaded, bool hasErrors, bool loadedFromSource, Sour /// public string ModelSourceFile => _modelSourceFile; + } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsContainerWithNestedContainers.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsContainerWithNestedContainers.cs index 687cd7f..b8f27a6 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsContainerWithNestedContainers.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsContainerWithNestedContainers.cs @@ -23,46 +23,53 @@ public abstract class CsContainerWithNestedContainers:CsContainer,ICsNestedConta #endregion /// - /// Constructor for the + /// Represents a container with nested containers in a C# code model, providing metadata about its structure, + /// attributes, generics, inheritance, and nested elements. /// - /// Flag that determines if the model was loaded. - /// Flag that determine if errors were found creating the model. - /// Flag that determines if the model was loaded from source code or from an existing library. - /// The target language the model was generated from. - /// The type of code model created. - /// The members assigned to this container. - /// Flag that determines if the container type is nested in another type definition. - /// Enumeration of the type of nesting the container is. - /// List of nested models assigned to this container. This is an optional parameter and can be null - /// The source document that was used to build this model. This is optional parameter and can be null. - /// Optional the lookup storage for models created during the compile or lookup of the model. - /// Optional the error that occurred while creating the model. - /// List of the attributes assigned to this model. - /// Flag that determines if the container is a generic definition. - /// Flag that determines if the generics use strong type definitions. - /// Generic parameters assigned to the container. - /// Target types for the generic parameters assigned to the container. - /// The source file the model was loaded from. - /// List of the fully qualified paths to the source code files this model is defined in. - /// Flag that determines if the model has XML documentation assigned to it. - /// The xml documentation assigned to the model. - /// The fully qualified model lookup path for this model. - /// The name of the model. - /// The namespace the container belongs to. - /// The fully qualified lookup path for the parent model to this one. - /// The type of container this model represents. - /// The security scope assigned to this model. - /// The interfaces that are inherited by this container. + /// This class is used to model a container (such as a class, struct, or interface) that + /// may contain nested containers or members. It provides detailed information about the container's attributes, + /// generic parameters, inheritance hierarchy, and nested elements. The container can be part of a larger code + /// model and may include documentation and source file references. + /// Indicates whether the container has been successfully loaded into the model. + /// Indicates whether the container contains any errors during loading or processing. + /// Indicates whether the container was loaded directly from source code. + /// The programming language of the source code (e.g., C#). + /// The type of the model this container belongs to. + /// A read-only list of attributes applied to the container. + /// Indicates whether the container is a generic type. + /// Indicates whether the container's generic parameters have strong type constraints. + /// A read-only list of generic parameters defined by the container. + /// A read-only list of generic types used by the container. + /// The file path of the source file where the container is defined. + /// A read-only list of source files associated with the container. + /// Indicates whether the container includes documentation comments. + /// The documentation comments associated with the container, if available. + /// The lookup path used to identify the container within the model hierarchy. + /// The name of the container. + /// The namespace to which the container belongs. + /// The path to the parent container, if the container is nested. + /// The type of the container (e.g., class, struct, interface). + /// The security level (access modifier) of the container. + /// A read-only list of all interfaces inherited by the container. + /// A read-only list of interfaces directly inherited by the container. + /// A read-only list of members (e.g., methods, properties) defined within the container. + /// Indicates whether the container is nested within another container. + /// The type of nesting for the container, if applicable. + /// A read-only list of nested models contained within the container. Defaults to an empty list if no nested + /// models are present. + /// The source document associated with the container, if available. + /// The model store containing the container and related models, if applicable. + /// A read-only list of errors encountered while loading the container model, if any. protected CsContainerWithNestedContainers(bool isLoaded, bool hasErrors, bool loadedFromSource, SourceCodeType language, CsModelType modelType, IReadOnlyList attributes, bool isGeneric, bool hasStrongTypesInGenerics, IReadOnlyList genericParameters, IReadOnlyList genericTypes, string modelSourceFile, IReadOnlyList sourceFiles, bool hasDocumentation, string documentation, string lookupPath, string name, string ns, string parentPath, CsContainerType containerType, CsSecurity security, - IReadOnlyList inheritedInterfaces, IReadOnlyList members, bool isNested, CsNestedType nestedType, IReadOnlyList nestedModels = null, + IReadOnlyList inheritedInterfaces,IReadOnlyList directInheritedInterfaces, IReadOnlyList members, bool isNested, CsNestedType nestedType, IReadOnlyList nestedModels = null, string sourceDocument = null, ModelStore modelStore = null, IReadOnlyList modelErrors = null) :base(isLoaded, hasErrors, loadedFromSource, language, modelType, attributes, isGeneric, hasStrongTypesInGenerics, genericParameters, genericTypes, modelSourceFile, sourceFiles, hasDocumentation, documentation, lookupPath, name, ns, parentPath, containerType, security, - inheritedInterfaces, members, sourceDocument, modelStore, modelErrors) + inheritedInterfaces,directInheritedInterfaces, members, sourceDocument, modelStore, modelErrors) { _isNested = isNested; _nestedType = nestedType; diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsInterface.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsInterface.cs index f0f6601..9ce0e51 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsInterface.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsInterface.cs @@ -14,44 +14,50 @@ namespace CodeFactory.WinVs.Models.CSharp public abstract class CsInterface:CsContainerWithNestedContainers,ICsInterface { /// - /// Constructor for the + /// Initializes a new instance of the class, representing a C# interface model with + /// metadata and structural details. /// - /// Flag that determines if the model was loaded. - /// Flag that determine if errors were found creating the model. - /// Flag that determines if the model was loaded from source code or from an existing library. - /// The target language the model was generated from. - /// The members assigned to this container. - /// Flag that determines if the container type is nested in another type definition. - /// Enumeration of the type of nesting the container is. - /// List of nested models assigned to this container. This is an optional parameter and can be null - /// The source document that was used to build this model. This is optional parameter and can be null. - /// Optional the lookup storage for models created during the compile or lookup of the model. - /// Optional the error that occurred while creating the model. - /// List of the attributes assigned to this model. - /// Flag that determines if the container is a generic definition. - /// Flag that determines if the generics use strong type definitions. - /// Generic parameters assigned to the container. - /// Target types for the generic parameters assigned to the container. - /// The source file the model was generated from. - /// List of the fully qualified paths to the source code files this model is defined in. - /// Flag that determines if the model has XML documentation assigned to it. - /// The xml documentation assigned to the model. - /// The fully qualified model lookup path for this model. - /// The name of the model. - /// The namespace the container belongs to. - /// The fully qualified lookup path for the parent model to this one. - /// The security scope assigned to this model. - /// The interfaces that are inherited by this container. + /// This constructor is protected and is intended to be used by derived classes to + /// initialize a instance with detailed metadata and structural information. The base + /// class constructor is invoked to handle common initialization logic. + /// Indicates whether the interface model has been successfully loaded. + /// Indicates whether the interface model contains any errors. + /// Indicates whether the interface was loaded directly from source code. + /// The programming language of the source code, represented as a . + /// A read-only list of attributes applied to the interface. + /// Indicates whether the interface is generic. + /// Indicates whether the generic parameters of the interface are strongly typed. + /// A read-only list of generic parameters defined by the interface. + /// A read-only list of generic types used by the interface. + /// The file path of the primary source file for the interface model. + /// A read-only list of source files associated with the interface. + /// Indicates whether the interface has associated XML documentation. + /// The XML documentation string for the interface, if available. + /// The lookup path used to uniquely identify the interface within the model hierarchy. + /// The name of the interface. + /// The namespace to which the interface belongs. + /// The lookup path of the parent container, if the interface is nested. + /// The security level of the interface, represented as a value. + /// A read-only list of all interfaces inherited by this interface. + /// A read-only list of interfaces directly inherited by this interface (excluding transitive inheritance). + /// A read-only list of members (methods, properties, events, etc.) defined in the interface. + /// Indicates whether the interface is nested within another type. + /// The type of nesting, represented as a value. + /// A read-only list of nested models contained within the interface, or if none exist. + /// The source document containing the interface definition, or if unavailable. + /// The model store containing additional metadata or related models, or if not provided. + /// A read-only list of errors encountered while loading the interface model, or if no + /// errors occurred. protected CsInterface(bool isLoaded, bool hasErrors, bool loadedFromSource, SourceCodeType language, IReadOnlyList attributes, bool isGeneric, bool hasStrongTypesInGenerics, IReadOnlyList genericParameters, IReadOnlyList genericTypes, string modelSourceFile, IReadOnlyList sourceFiles, bool hasDocumentation, string documentation, string lookupPath, string name, string ns, string parentPath, - CsSecurity security, IReadOnlyList inheritedInterfaces, + CsSecurity security, IReadOnlyList inheritedInterfaces, IReadOnlyList directInheritedInterfaces, IReadOnlyList members, bool isNested,CsNestedType nestedType, IReadOnlyList nestedModels = null, string sourceDocument = null, ModelStore modelStore = null, IReadOnlyList modelErrors = null) : base(isLoaded, hasErrors, loadedFromSource, language, CsModelType.Interface,attributes, isGeneric, hasStrongTypesInGenerics, genericParameters, genericTypes,modelSourceFile, sourceFiles, hasDocumentation, - documentation, lookupPath, name, ns, parentPath, CsContainerType.Interface, security, inheritedInterfaces, + documentation, lookupPath, name, ns, parentPath, CsContainerType.Interface, security, inheritedInterfaces, directInheritedInterfaces, members,isNested,nestedType,nestedModels, sourceDocument, modelStore, modelErrors) { //Intentionally blank diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsRecord.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsRecord.cs index 3121e58..3220971 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsRecord.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsRecord.cs @@ -23,45 +23,51 @@ public abstract class CsRecord:CsContainer,ICsRecord #endregion /// - /// Constructor for the + /// Initializes a new instance of the class, representing a C# record type with its + /// associated metadata and characteristics. /// - /// Flag that determines if the model was loaded. - /// Flag that determine if errors were found creating the model. - /// Flag that determines if the model was loaded from source code or from an existing library. - /// The target language the model was generated from. - /// The members assigned to this container. - /// The record model that is base record of this record. - /// The source document that was used to build this model. This is optional parameter and can be null. - /// Optional the lookup storage for models created during the compile or lookup of the model. - /// Optional the error that occurred while creating the model. - /// List of the attributes assigned to this model. - /// Flag that determines if the container is a generic definition. - /// Flag that determines if the generics use strong type definitions. - /// Generic parameters assigned to the container. - /// Target types for the generic parameters assigned to the container. - /// The source code file the model was generated from. - /// List of the fully qualified paths to the source code files this model is defined in. - /// Flag that determines if the model has XML documentation assigned to it. - /// The xml documentation assigned to the model. - /// The fully qualified model lookup path for this model. - /// The name of the model. - /// The namespace the container belongs to. - /// The fully qualified lookup path for the parent model to this one. - /// The security scope assigned to this model. - /// The interfaces that are inherited by this container. - /// Flag that determines if the model is static. - /// Flag that determines if the model is abstract. - /// Flag that determines if the model is sealed. + /// This constructor is primarily used to initialize a instance + /// with detailed metadata about the record, including its attributes, generic parameters, inheritance, and + /// members. It is typically used in scenarios where a comprehensive representation of a C# record is required, + /// such as code analysis or generation tools. + /// Indicates whether the record has been successfully loaded. + /// Indicates whether the record contains any errors. + /// Indicates whether the record was loaded from source code. + /// The programming language of the source code, typically C#. + /// A read-only list of attributes applied to the record. + /// Indicates whether the record is a generic type. + /// Indicates whether the generic parameters of the record are strongly typed. + /// A read-only list of generic parameters defined by the record. + /// A read-only list of generic types used by the record. + /// The file path of the primary source file for the record's model. + /// A read-only list of source files associated with the record. + /// Indicates whether the record has associated documentation. + /// The documentation string associated with the record, if available. + /// The lookup path used to identify the record within the model. + /// The name of the record. + /// The namespace in which the record is defined. + /// The path to the parent container of the record, if applicable. + /// The security level (accessibility) of the record, such as public or private. + /// A read-only list of all interfaces inherited by the record, including indirect inheritance. + /// A read-only list of interfaces directly inherited by the record. + /// A read-only list of members (fields, properties, methods, etc.) defined within the record. + /// Indicates whether the record is static. + /// Indicates whether the record is abstract. + /// Indicates whether the record is sealed. + /// The base record from which this record inherits, if any. + /// The source document associated with the record, if available. This parameter is optional. + /// The model store containing the record, if applicable. This parameter is optional. + /// A read-only list of errors encountered while loading the record's model, if any. This parameter is optional. protected CsRecord(bool isLoaded, bool hasErrors, bool loadedFromSource, SourceCodeType language, IReadOnlyList attributes, bool isGeneric, bool hasStrongTypesInGenerics, IReadOnlyList genericParameters, IReadOnlyList genericTypes, string modelSourceFile, IReadOnlyList sourceFiles, bool hasDocumentation, string documentation, string lookupPath, string name, string ns, string parentPath, - CsSecurity security, IReadOnlyList inheritedInterfaces, IReadOnlyList members, + CsSecurity security, IReadOnlyList inheritedInterfaces, IReadOnlyList directInheritedInterfaces, IReadOnlyList members, bool isStatic, bool isAbstract, bool isSealed, CsRecord baseRecord,string sourceDocument = null, ModelStore modelStore = null, IReadOnlyList modelErrors = null) : base(isLoaded, hasErrors, loadedFromSource, language, CsModelType.Record, attributes, isGeneric, hasStrongTypesInGenerics, genericParameters, genericTypes, modelSourceFile, sourceFiles, hasDocumentation, - documentation, lookupPath, name, ns, parentPath, CsContainerType.Record, security, inheritedInterfaces, + documentation, lookupPath, name, ns, parentPath, CsContainerType.Record, security, inheritedInterfaces, directInheritedInterfaces, members,sourceDocument, modelStore, modelErrors) { _isStatic = isStatic; diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsRecordStructure.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsRecordStructure.cs index ee22f5d..6d65b3c 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsRecordStructure.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsRecordStructure.cs @@ -16,40 +16,42 @@ namespace CodeFactory.WinVs.Models.CSharp public abstract class CsRecordStructure:CsContainer,ICsRecordStructure { /// - /// Constructor for the + /// Initializes a new instance of the class, representing a record structure in + /// the source code model. /// - /// Flag that determines if the model was loaded. - /// Flag that determine if errors were found creating the model. - /// Flag that determines if the model was loaded from source code or from an existing library. - /// The target language the model was generated from. - /// The members assigned to this container. - /// The source document that was used to build this model. This is optional parameter and can be null. - /// Optional the lookup storage for models created during the compile or lookup of the model. - /// Optional the error that occurred while creating the model. - /// List of the attributes assigned to this model. - /// Flag that determines if the container is a generic definition. - /// Flag that determines if the generics use strong type definitions. - /// Generic parameters assigned to the container. - /// Target types for the generic parameters assigned to the container. - /// The source file the model was generated from. - /// List of the fully qualified paths to the source code files this model is defined in. - /// Flag that determines if the model has XML documentation assigned to it. - /// The xml documentation assigned to the model. - /// The fully qualified model lookup path for this model. - /// The name of the model. - /// The namespace the container belongs to. - /// The fully qualified lookup path for the parent model to this one. - /// The security scope assigned to this model. - /// The interfaces that are inherited by this container. + /// Indicates whether the record structure has been successfully loaded. + /// Indicates whether the record structure contains errors. + /// Indicates whether the record structure was loaded from a source file. + /// The programming language of the source code. + /// A read-only list of attributes applied to the record structure. + /// Indicates whether the record structure is generic. + /// Indicates whether the generic parameters of the record structure are strongly typed. + /// A read-only list of generic parameters defined by the record structure. + /// A read-only list of generic types used by the record structure. + /// The file path of the primary source file for the record structure. + /// A read-only list of source files associated with the record structure. + /// Indicates whether the record structure has associated documentation. + /// The documentation string associated with the record structure, if available. + /// The lookup path used to identify the record structure in the model. + /// The name of the record structure. + /// The namespace to which the record structure belongs. + /// The lookup path of the parent container, if applicable. + /// The security level (accessibility) of the record structure. + /// A read-only list of all interfaces inherited by the record structure, including indirect inheritance. + /// A read-only list of interfaces directly inherited by the record structure. + /// A read-only list of members (fields, properties, methods, etc.) defined in the record structure. + /// The source document containing the record structure, if available. + /// The model store associated with the record structure, if applicable. + /// A read-only list of errors encountered while loading the record structure, if any. protected CsRecordStructure(bool isLoaded, bool hasErrors, bool loadedFromSource, SourceCodeType language, IReadOnlyList attributes, bool isGeneric, bool hasStrongTypesInGenerics, IReadOnlyList genericParameters, IReadOnlyList genericTypes, string modelSourceFile, IReadOnlyList sourceFiles, bool hasDocumentation, string documentation, string lookupPath, string name, string ns, string parentPath, - CsSecurity security, IReadOnlyList inheritedInterfaces, IReadOnlyList members, + CsSecurity security, IReadOnlyList inheritedInterfaces, IReadOnlyList directInheritedInterfaces, IReadOnlyList members, string sourceDocument = null, ModelStore modelStore = null, IReadOnlyList modelErrors = null) : base(isLoaded, hasErrors, loadedFromSource, language, CsModelType.RecordStructure, attributes, isGeneric, hasStrongTypesInGenerics, genericParameters, genericTypes, modelSourceFile, sourceFiles, hasDocumentation, - documentation, lookupPath, name, ns, parentPath, CsContainerType.RecordStructure, security, inheritedInterfaces, members, + documentation, lookupPath, name, ns, parentPath, CsContainerType.RecordStructure, security, inheritedInterfaces, directInheritedInterfaces, members, sourceDocument, modelStore, modelErrors) { //Intentionally blank diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs index 7b272e6..8594968 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsSearchContainer.cs @@ -10,71 +10,146 @@ namespace CodeFactory.WinVs.Models.CSharp /// public class CsSearchContainer { + #region Backing fields for properties + private readonly string _filePath; + + private readonly string _namespace; + + private readonly string _name; + + private readonly CsSecurity _security; + + private readonly CsContainerType _containerType; + + private readonly bool _isGenericContainer; + + private readonly IReadOnlyList _genericParameters; + + private readonly bool _hasStrongTypesInGenerics; + + private readonly IReadOnlyList _genericTypes; + + private readonly bool _hasBaseClass; + + private readonly bool _hasInheritedInterfaces; + + private readonly bool _hasAttributes; + + private readonly IReadOnlyList _attributes; + + #endregion + + /// + /// Initializes a new instance of the class, representing a container for C# + /// code elements with metadata about its structure, type, and attributes. + /// + /// The file path where the container is defined. Cannot be null or empty. + /// The namespace of the container. Cannot be null or empty. + /// The name of the container. Cannot be null or empty. + /// The access modifier of the container (e.g., public, private). Must be a valid + /// value. + /// The type of the container (e.g., class, struct, interface). Must be a valid + /// value. + /// A value indicating whether the container is a generic type. if the container is + /// generic; otherwise, . + /// A read-only list of generic parameters defined by the container. If the container is not generic, this list + /// will be empty. + /// A value indicating whether the generic parameters include strong types. if strong + /// types are present; otherwise, . + /// A read-only list of generic types used by the container. If the container does not use generic types, this + /// list will be empty. + /// A value indicating whether the container has a base class. if a base class is + /// present; otherwise, . + /// A value indicating whether the container inherits from any interfaces. if inherited + /// interfaces are present; otherwise, . + /// A value indicating whether the container has any attributes applied. if attributes + /// are present; otherwise, . + /// A read-only list of attributes applied to the container. If no attributes are present, this list will be + /// empty. + public CsSearchContainer(string filePath, string ns, string name, CsSecurity security, CsContainerType containerType, + bool isGenericContainer, IReadOnlyList genericParameters, bool hasStrongTypesInGenerics, + IReadOnlyList genericTypes, bool hasBaseClass, bool hasInheritedInterfaces, bool hasAttributes, + IReadOnlyList attributes) + { + _filePath = filePath; + _namespace = ns; + _name = name; + _security = security; + _containerType = containerType; + _isGenericContainer = isGenericContainer; + _genericParameters = genericParameters ?? ImmutableList.Empty; + _hasStrongTypesInGenerics = hasStrongTypesInGenerics; + _genericTypes = genericTypes ?? ImmutableList.Empty; + _hasBaseClass = hasBaseClass; + _hasInheritedInterfaces = hasInheritedInterfaces; + _hasAttributes = hasAttributes; + _attributes = attributes ?? ImmutableList.Empty; + } /// /// The file path of the C# container represented by this instance. /// - public string FilePath { get; init; } = null; + public string FilePath => _filePath; /// /// The namespace the C# cntainer is defined in. /// - public string Namespace { get; init; } + public string Namespace => _namespace; /// /// Gets the name of the container associated with the current instance. /// - public string Name { get; init; } + public string Name => _name; /// /// The security scope of the container represented by this instance. /// - CsSecurity Security { get; init; } = CsSecurity.Unknown; + public CsSecurity Security => _security; /// /// Gets the type of the container represented by this instance. /// - public CsContainerType ContainerType { get; init; } = CsContainerType.Unknown; + public CsContainerType ContainerType => _containerType; /// /// Flag that determines if this container has a generic type definition. /// - public bool IsGenericContainer { get; init; } = false; + public bool IsGenericContainer => _isGenericContainer; /// /// List of the generic parameters defined for the container. /// - public IReadOnlyList GenericParameters { get; init; } = ImmutableList.Empty; + public IReadOnlyList GenericParameters => _genericParameters; /// /// Flag that determines if the container has strong types defined in its generic parameters. /// - public bool HasStrongTypesInGenerics { get; init; } = false; + public bool HasStrongTypesInGenerics => _hasStrongTypesInGenerics; /// /// List of the generic types defined for the container. /// - public IReadOnlyList GenericTypes { get; init; } = ImmutableList.Empty; + public IReadOnlyList GenericTypes => _genericTypes; /// /// Flag that determines if the container has a base class defined. /// - public bool HasBaseClass { get; init; } = false; + public bool HasBaseClass => _hasBaseClass; /// /// Flag that determines if the container inherits from any interfaces. /// - public bool HasInheritedInterfaces { get; init; } = false; + public bool HasInheritedInterfaces => _hasInheritedInterfaces; /// /// Flag that determines if the container has any attributes defined. /// - public bool HasAttributes { get; init; } = false; + public bool HasAttributes => _hasAttributes; /// /// List of the attributes defined for the container. /// - public IReadOnlyList Attributes { get; init; } = ImmutableList.Empty; + public IReadOnlyList Attributes => _attributes; } } diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsStructure.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsStructure.cs index afb10e0..6ea1d75 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsStructure.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/CsStructure.cs @@ -16,44 +16,46 @@ namespace CodeFactory.WinVs.Models.CSharp public abstract class CsStructure:CsContainerWithNestedContainers,ICsStructure { /// - /// Constructor for the + /// Initializes a new instance of the class, representing a C# structure with metadata + /// about its attributes, generics, inheritance, members, and other characteristics. /// - /// Flag that determines if the model was loaded. - /// Flag that determine if errors were found creating the model. - /// Flag that determines if the model was loaded from source code or from an existing library. - /// The target language the model was generated from. - /// The members assigned to this container. - /// Flag that determines if the container type is nested in another type definition. - /// Enumeration of the type of nesting the container is. - /// List of nested models assigned to this container. This is an optional parameter and can be null - /// The source document that was used to build this model. This is optional parameter and can be null. - /// Optional the lookup storage for models created during the compile or lookup of the model. - /// Optional the error that occurred while creating the model. - /// List of the attributes assigned to this model. - /// Flag that determines if the container is a generic definition. - /// Flag that determines if the generics use strong type definitions. - /// Generic parameters assigned to the container. - /// Target types for the generic parameters assigned to the container. - /// The source file the model was generated from. - /// List of the fully qualified paths to the source code files this model is defined in. - /// Flag that determines if the model has XML documentation assigned to it. - /// The xml documentation assigned to the model. - /// The fully qualified model lookup path for this model. - /// The name of the model. - /// The namespace the container belongs to. - /// The fully qualified lookup path for the parent model to this one. - /// The security scope assigned to this model. - /// The interfaces that are inherited by this container. + /// Indicates whether the structure has been successfully loaded. + /// Indicates whether the structure contains errors. + /// Indicates whether the structure was loaded from source code. + /// The programming language of the source code, typically C#. + /// A read-only list of attributes applied to the structure. + /// Indicates whether the structure is a generic type. + /// Indicates whether the generic parameters of the structure are strongly typed. + /// A read-only list of generic parameters defined by the structure. + /// A read-only list of generic types used by the structure. + /// The file path of the source file where the structure is defined. + /// A read-only list of source files associated with the structure. + /// Indicates whether the structure has associated XML documentation. + /// The XML documentation associated with the structure, if available. + /// The lookup path used to identify the structure within the model hierarchy. + /// The name of the structure. + /// The namespace in which the structure is defined. + /// The path to the parent container of the structure, if applicable. + /// The security level (accessibility) of the structure, such as public or internal. + /// A read-only list of all interfaces inherited by the structure, including indirect inheritance. + /// A read-only list of interfaces directly inherited by the structure. + /// A read-only list of members (fields, properties, methods, etc.) defined in the structure. + /// Indicates whether the structure is nested within another type. + /// The type of nesting, if the structure is nested. + /// A read-only list of nested models contained within the structure, if any. This parameter is optional. + /// The source document associated with the structure, if available. This parameter is optional. + /// The model store containing additional metadata or related models. This parameter is optional. + /// A read-only list of errors encountered while loading the structure. This parameter is optional. protected CsStructure(bool isLoaded, bool hasErrors, bool loadedFromSource, SourceCodeType language, IReadOnlyList attributes, bool isGeneric, bool hasStrongTypesInGenerics, IReadOnlyList genericParameters, IReadOnlyList genericTypes, string modelSourceFile, IReadOnlyList sourceFiles, bool hasDocumentation, string documentation, string lookupPath, string name, string ns, string parentPath, - CsSecurity security, IReadOnlyList inheritedInterfaces, IReadOnlyList members,bool isNested,CsNestedType nestedType,IReadOnlyList nestedModels = null, + CsSecurity security, IReadOnlyList inheritedInterfaces, IReadOnlyList directInheritedInterfaces, IReadOnlyList members,bool isNested,CsNestedType nestedType,IReadOnlyList nestedModels = null, string sourceDocument = null, ModelStore modelStore = null, IReadOnlyList modelErrors = null) : base(isLoaded, hasErrors, loadedFromSource, language, CsModelType.Structure, attributes, isGeneric, hasStrongTypesInGenerics, genericParameters, genericTypes, modelSourceFile, sourceFiles, hasDocumentation, - documentation, lookupPath, name, ns, parentPath, CsContainerType.Structure, security, inheritedInterfaces, members,isNested,nestedType, + documentation, lookupPath, name, ns, parentPath, CsContainerType.Structure, security, inheritedInterfaces, directInheritedInterfaces, members,isNested,nestedType, nestedModels, sourceDocument, modelStore, modelErrors) { //Intentionally blank diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/ICsContainer.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/ICsContainer.cs index 356b6b3..835ed20 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/ICsContainer.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Models/CSharp/ICsContainer.cs @@ -39,6 +39,11 @@ public interface ICsContainer: ICsModel,ISourceFiles, ICsAttributes,IDocumentati /// IReadOnlyList InheritedInterfaces { get; } + /// + /// List of the interfaces that are directly inherited by this container. This does not include interfaces that are inherited by base classes. Or interfaces that are inherited by other interfaces that this container inherits from. + /// + IReadOnlyList DirectInheritedInterfaces { get; } + /// /// List of the members that are implemented in this container. /// diff --git a/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj b/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj index 242e28e..aa0c3a5 100644 --- a/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj +++ b/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj @@ -6,7 +6,7 @@ True CFSigner.snk True - 2.25206.0.1-PreRelease + 2.25214.0.1-PreRelease CodeFactory, LLC. CodeFactory, LLC. CodeFactory Base Library @@ -17,11 +17,11 @@ False CodeFactory Base Libraries 2.0.0.0 - 2.25206.0.1 + 2.25214.0.1 CFLogo128.png git - Release Updates for 2.25206.0.1 + Release Updates for 2.25214.0.1 Recompile Release: When you update your automation to this version of the SDK. From 584ecca620a20c36aae0b80547913117b60fd49f Mon Sep 17 00:00:00 2001 From: Stephen Giffin Date: Fri, 8 Aug 2025 11:54:45 -0700 Subject: [PATCH 4/4] Update versioning and enhance CodeFactory SDK features Updated version numbers in `.nuspec` and project files to `2.25220.0.1-PreRelease`. The `AssemblyFileVersion` in `AssemblyInfo.cs` has been synchronized with the new version. Minimum and maximum SDK version constants in `SdkSupport.cs` have been adjusted accordingly. Introduced new method `LoadExternalConfigAsync` in `VsActionsExtensions.cs` for loading external configuration commands. New classes and attributes for external configuration mapping have been added, including `CommandConfigAttribute` and various parameter configuration attributes. Enhanced `ExternalConfigMap` with additional properties and methods for managing configurations. Introduced `PropertySetter` for dynamic property value assignment and `ObjectNameTransformer` for managing object name transformations. Added extension methods to improve functionality in `CsClass`, `CsInterface`, and other C# model classes for better namespace and using statement management. Updated `CsFactoryManagement` to include methods for managing C# code elements and ensuring required using statements are present. Enhanced `CsSourceClassManager` with methods for adding syntax elements around fields and constructors. Overall, these changes improve the structure, functionality, and usability of the CodeFactory SDK, particularly regarding external configurations and C# code management. --- .../CodeFactoryWinVsSDK.nuspec | 10 +- .../Properties/AssemblyInfo.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- .../CodeFactory.WinVs.Wpf/WinVsWpf.nuspec | 8 +- .../CodeFactory.WinVs.csproj | 6 +- .../Commands/CommandConfigAttribute.cs | 56 + .../Commands/CommandExternalConfigMap.cs | 44 + .../ExecutionProjectConfigAttribute.cs | 39 + .../ExecutionProjectExternalConfigMap.cs | 34 + .../Commands/ExternalCommandConfig.cs | 690 ++++++ .../Commands/ExternalConfigAttribute.cs | 35 + .../Commands/ExternalConfigExtensions.cs | 370 +++ .../Commands/ExternalConfigMap.cs | 72 + .../Commands/ExternalConfigMapExtensions.cs | 405 ++++ .../Commands/ExternalConfigType.cs | 69 + .../ExternalProjectFolderConfigMap.cs | 43 + .../Commands/IPropertySetter.cs | 25 + .../Commands/ListValueConfigAttribute.cs | 22 + .../Commands/ParameterBoolConfigAttribute.cs | 57 + .../ParameterBoolExternalConfigMap.cs | 50 + .../Commands/ParameterDateConfigAttribute.cs | 56 + .../ParameterDateExternalConfigMap.cs | 50 + .../Commands/ParameterListConfigAttribute.cs | 52 + .../ParameterListExternalConfigMap.cs | 49 + .../ParameterSelectedValueConfigAttribute.cs | 55 + ...ParameterSelectedValueExternalConfigMap.cs | 53 + .../ParameterStringConfigAttribute.cs | 52 + .../ParameterStringExternalConfigMap.cs | 46 + .../Commands/ProjectConfigAttribute.cs | 45 + .../Commands/ProjectExternalConfigMap.cs | 35 + .../Commands/ProjectFolderConfigAttribute.cs | 59 + .../ProjectFolderExternalConfigMap.cs | 40 + .../Commands/PropertySetter.cs | 63 + .../Commands/StandardCommandCategories.cs | 46 + .../Factory/CSharp/CsClassExtensions.cs | 46 + .../Factory/CSharp/CsClassResult.cs | 87 + .../Factory/CSharp/CsContainerResult.cs | 87 + .../Factory/CSharp/CsFactoryManagement.cs | 807 +++++++ .../Factory/CSharp/CsInterfaceExtensions.cs | 88 + .../Factory/CSharp/CsInterfaceResult.cs | 86 + .../Factory/CSharp/CsRecordResult.cs | 88 + .../Factory/CSharp/CsSourceClassManager.cs | 250 ++ .../CSharp/CsSourceContainerManager.cs | 2027 +++++++++++++++++ .../CSharp/CsSourceInterfaceManager.cs | 127 ++ .../Factory/CSharp/CsSourceRecordManager.cs | 241 ++ .../Factory/CSharp/CsSourceResult.cs | 33 + .../CSharp/CsSourceStructureManager.cs | 227 ++ .../Factory/CSharp/CsSyntaxBuilder.cs | 24 + .../Factory/CSharp/ICsFactoryManagement.cs | 69 + .../Factory/CSharp/ICsFactoryRequest.cs | 21 + .../CSharp/ICsSourceContainerManager.cs | 41 + .../Factory/CSharp/ICsSourceManager.cs | 682 ++++++ .../Factory/CSharp/ICsSyntaxBuilder.cs | 24 + .../Factory/CSharp/ISourceResult.cs | 46 + .../Factory/CSharp/ISyntaxRequest.cs | 22 + .../Factory/CSharp/SourceResultExtensions.cs | 37 + .../Factory/ObjectNameTransformer.cs | 170 ++ .../CodeFactory.WinVs/ImmutableClass.cs | 44 + .../CodeFactory.WinVs/Loader/SdkSupport.cs | 6 +- .../CodeFactory.WinVs/VsActionsExtensions.cs | 78 + .../CodeFactory/CodeFactory.csproj | 6 +- .../CodeFactory/SourceFormatter.cs | 46 +- 62 files changed, 8229 insertions(+), 21 deletions(-) create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/CommandConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/CommandExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExecutionProjectConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExecutionProjectExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalCommandConfig.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigExtensions.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigMapExtensions.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigType.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalProjectFolderConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/IPropertySetter.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ListValueConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterBoolConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterBoolExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterDateConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterDateExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterListConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterListExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterSelectedValueConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterSelectedValueExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterStringConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterStringExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectFolderConfigAttribute.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectFolderExternalConfigMap.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/PropertySetter.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/StandardCommandCategories.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsClassExtensions.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsClassResult.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsContainerResult.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsFactoryManagement.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsInterfaceExtensions.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsInterfaceResult.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsRecordResult.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceClassManager.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceContainerManager.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceInterfaceManager.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceRecordManager.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceResult.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceStructureManager.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSyntaxBuilder.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsFactoryManagement.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsFactoryRequest.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSourceContainerManager.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSourceManager.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSyntaxBuilder.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ISourceResult.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ISyntaxRequest.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/SourceResultExtensions.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/ObjectNameTransformer.cs create mode 100644 Src/CodeFactoryForWindows/CodeFactory.WinVs/ImmutableClass.cs diff --git a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec index 3d1848b..7028198 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec +++ b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/CodeFactoryWinVsSDK.nuspec @@ -2,7 +2,7 @@ CodeFactory.WinVs.SDK - 2.25214.0.1-PreRelease + 2.25220.0.1-PreRelease CodeFactory Software Development Kit for Visual Studio - Windows CodeFactory, LLC. CodeFactory, LLC. @@ -10,7 +10,7 @@ true Software development kit for building CodeFactory automation in Visual Studio - Windows. - Release Updates for 2.25214.0.1 + Release Updates for 2.25220.0.1 Recompile Release: When you update your automation to this version of the SDK. @@ -40,9 +40,9 @@ Copyright © 2025 CodeFactory, LLC. Factory Automation - - - + + + CFLogo128.png diff --git a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs index 9af97e4..d56aef5 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.Packager.WinVs/Properties/AssemblyInfo.cs @@ -33,4 +33,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.25214.0.1")] +[assembly: AssemblyFileVersion("2.25220.0.1")] diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs index 26a4726..edfe56b 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/Properties/AssemblyInfo.cs @@ -33,4 +33,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.25214.0.1")] +[assembly: AssemblyFileVersion("2.25220.0.1")] diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec index 53ef8bc..1f9f569 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs.Wpf/WinVsWpf.nuspec @@ -2,7 +2,7 @@ CodeFactory.WinVs.Wpf - 2.25214.0.1-PreRelease + 2.25220.0.1-PreRelease CodeFactory User Interface WPF for Visual Studio - Windows CodeFactory, LLC. CodeFactory, LLC. @@ -10,7 +10,7 @@ true Library that provides custom dialog screens hosted in Visual Studio for Windows, hosted for CodeFactory automation. - Release Updates for 2.25214.0.1 + Release Updates for 2.25220.0.1 Recompile Release: When you update your automation to this version of the SDK. @@ -19,8 +19,8 @@ Copyright © 2025 CodeFactory, LLC. Factory Automation - - + + CFLogo128.png diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj b/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj index b428b62..851863d 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/CodeFactory.WinVs.csproj @@ -6,7 +6,7 @@ True CFSigner.snk True - 2.25214.0.1-PreRelease + 2.25220.0.1-PreRelease CodeFactory, LLC. CodeFactory, LLC. CodeFactory Base Library @@ -17,10 +17,10 @@ False CodeFactory API for Visual Studio - Windows 2.0.0.0 - 2.25214.0.1 + 2.25220.0.1 CFLogo128.png - Release Updates for 2.25214.0.1 + Release Updates for 2.25220.0.1 Recompile Release: When you update your automation to this version of the SDK. diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/CommandConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/CommandConfigAttribute.cs new file mode 100644 index 0000000..b43e433 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/CommandConfigAttribute.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies metadata for a command configuration, including its name, associated command type, guidance text, and + /// optional documentation URL. This attribute is applied to classes to define their command configuration details. + /// + /// Use this attribute to annotate classes that represent command configurations. The metadata + /// provided by this attribute can be used to categorize commands, associate them with specific command types, and + /// provide additional guidance or documentation for users. + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class CommandConfigAttribute:ExternalConfigAttribute + { + + /// + /// Initializes a new instance of the class. + /// + /// This attribute is used to specify that the associated member represents a command + /// configuration. It is primarily intended for use in scenarios where external configuration types need to be + /// explicitly defined. + public CommandConfigAttribute(): base(ExternalConfigType.Command) + { + //Intentionally left blank, this is used to define the type of external configuration this attribute represents. + } + + /// + /// The name of the command configuration. + /// + public string Name { get; set; } + + /// + /// The type of the command that supports this configuration. + /// + public Type SupportingCommand { get; set; } + + /// + /// Gets the guidance text associated with the command configuration. This can provide additional context or instructions for users. + /// + public string Guidance { get; set; } + + /// + /// Gets or sets the URL that provides additional guidance or documentation. + /// + public string GuidanceUrl { get; set; } + + /// + /// The category of the command configuration, which can be used to group similar commands together. + /// + public string Category { get; set; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/CommandExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/CommandExternalConfigMap.cs new file mode 100644 index 0000000..4364dfc --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/CommandExternalConfigMap.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Represents an external configuration map for a command, including its type, guidance, and related documentation. + /// + /// This class is used to define the configuration details for a specific command, including its + /// name, type, optional guidance text, and an optional URL for additional documentation. It extends the class and is specifically tailored for command-related configurations. + public class CommandExternalConfigMap: ExternalConfigMap + { + /// + /// Initializes a new instance of the class with the specified name, + /// command type, guidance, and guidance URL. + /// + /// The name of the external configuration command. Cannot be null or empty. + /// The type of the command represented by this configuration. Cannot be null or empty. + /// The category assoicated with the command configuration. + /// The guidance text associated with the command. This can provide additional context or instructions. Can be + /// null. + /// The URL pointing to detailed guidance or documentation for the command. Can be null. + public CommandExternalConfigMap( string name, string commandType, string category, string guidance, string guidanceUrl):base(ExternalConfigType.Command,name,false,guidance,guidanceUrl,null) + { + CommandType = commandType; + Category = category; + } + + /// + /// The fully qualified type name of the command that supports this configuration. + /// + public string CommandType { get; init; } + + /// + /// Gets or sets the category associated with the command configuration. This can be used to group similar commands together. + /// + public string Category { get; set; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExecutionProjectConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExecutionProjectConfigAttribute.cs new file mode 100644 index 0000000..b857411 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExecutionProjectConfigAttribute.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies that a property represents a configuration setting for an execution project. + /// + /// This attribute is intended to be applied to properties to indicate their role in defining + /// configuration settings for execution projects. It can only be applied to properties and does not support + /// multiple instances on the same property. + [AttributeUsage (AttributeTargets.Property, AllowMultiple = false,Inherited = true)] + public class ExecutionProjectConfigAttribute: ExternalConfigAttribute + { + /// + /// Specifies that the associated member is configured to use the "ExecuteProject" external configuration type. + /// + /// This attribute is used to indicate that a member is associated with the + /// "ExecuteProject" configuration type. It is primarily intended for use in scenarios where external + /// configuration types are categorized and processed. + public ExecutionProjectConfigAttribute() : base(ExternalConfigType.ExecuteProject) + { + // Intentionally left blank, this is used to define the type of external configuration this attribute represents. + } + + /// + /// Gets the guidance text associated with the command configuration. This can provide additional context or instructions for users. + /// + public string Guidance { get; set; } = "The project the automation command will execute from."; + + /// + /// Gets or sets the URL that provides additional guidance or documentation. + /// + public string GuidanceUrl { get; set; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExecutionProjectExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExecutionProjectExternalConfigMap.cs new file mode 100644 index 0000000..90656d8 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExecutionProjectExternalConfigMap.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Represents an external configuration map specific to execution projects, providing guidance and a mechanism to + /// set configuration values. + /// + /// This class is a specialized implementation of designed for + /// execution project configurations. It includes guidance text, an optional guidance URL, and a delegate for + /// setting configuration values dynamically. + public class ExecutionProjectExternalConfigMap : ExternalConfigMap + { + /// + /// Initializes a new instance of the class with the specified + /// name, guidance, guidance URL, and configuration value setter. + /// + /// The name of the external configuration map. + /// The guidance text associated with the configuration map. + /// The URL providing additional guidance for the configuration map. + /// An action delegate used to set the configuration value. The first parameter represents the target object, + /// and the second parameter represents the value to set. + public ExecutionProjectExternalConfigMap(string name, string guidance, string guidanceUrl, IPropertySetter setConfigurationValue) : base(ExternalConfigType.ExecuteProject, name, true, guidance, guidanceUrl, setConfigurationValue) + { + //Intentionally blank + } + + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalCommandConfig.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalCommandConfig.cs new file mode 100644 index 0000000..5d2c7a5 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalCommandConfig.cs @@ -0,0 +1,690 @@ + +using CodeFactory.WinVs.Models.ProjectSystem; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Provides an abstract base class for defining and managing external command configurations. + /// + /// This class is designed to facilitate the creation and management of command configurations by + /// leveraging external configuration maps. It includes functionality for loading, caching, and processing + /// configuration data, as well as creating project and execution configurations. + /// The type representing a CodeFactory command that is supported by this configuration. Must be a reference type. + /// The configuration class that is supported by this base class. Must be a class and have + /// a parameterless constructor. + public abstract class ExternalCommandConfig where C : class where E : class, new() + { + /// + /// List of external configuration maps that define the command configuration. Used as a static cache to avoid multiple reflection calls. + /// + private static ImmutableList _configurationMap = null; + + /// + /// Represents a static, immutable instance of a configuration command. + /// + /// This field is intended to store a single, thread-safe instance of an immutable + /// configuration command. It is initialized to and should be assigned a valid instance + /// before use. + private static ImmutableClass _configCommand = null; + + /// + /// Represents the fully qualified name of the type . + /// + /// This field is used to store the name of the type as a string. It is + /// initialized using the property. + private static string commandType = typeof(C).FullName; + + /// + /// Loads the configuration command for the specified command type. + /// + /// This method initializes and returns a configuration command instance. If the + /// configuration command has already been loaded, it returns the cached instance. If the configuration map is + /// not loaded, it attempts to load it before creating the configuration command. + /// An instance of representing the loaded configuration command. + /// Thrown if the configuration command cannot be created for the specified command type. + public static ConfigCommand LoadConfigCommand() + { + if (_configCommand != null) return _configCommand.Value; + + if (_configurationMap == null) LoadExternalMap(); + + var configCommand = CreateConfigCommand(); + + //if (configCommand == null) throw new CodeFactoryException($"Could not create the command configuration for the command type: {commandType}, cannot create the command configuration."); + + _configCommand = new ImmutableClass(configCommand); + + return configCommand; + + } + + /// + /// Initializes and loads the configuration for a command asynchronously. + /// + /// This method performs the following steps: + /// Loads the external configuration for the specified command type. + /// Maps the external configuration to the corresponding configuration object of type + /// . Populates the configuration object with + /// parameter and project values, if available. If the command does not support + /// external configuration or the configuration map is unavailable, the method returns . + /// An instance of used to perform Visual Studio-related actions, such as loading + /// external configurations. + /// The result of the command execution, containing metadata and context for the command. + /// A task that represents the asynchronous operation. The task result is an instance of containing the loaded configuration, or if the configuration could not be + /// loaded. + public static async Task InitAsync(IVsActions vsActions, VsModel commandResult) + { + + var commandType = typeof(C).FullName; + + + //Loads the external configuration for this command, this will return null if the command does not support external configuration. + //This also checks if the C# source is in a project folder, if so it will load the configuration based on the folder structure. + var command = await vsActions.LoadExternalConfigAsync(commandType, commandResult, true); + + if(command == null) return null; + + //Loading the external configuration map for the command type. + var commandMap = _configurationMap.GetCommandExternalConfigMap(); + + if (commandMap == null) return null; + + var config = new E(); + + + if(command.Parameters != null && command.Parameters.Any()) + { + //Setting the parameter values in the confguration that are defined in the external configuration map. + SetParameterValuesForParent(command.Parameters, commandMap.Name, config); + + } + + var executionProject = command.ExecutionProject; + + if (executionProject != null) await SetProjectValues(vsActions, executionProject, config,true); + + if(command.Projects != null && command.Projects.Any()) + { + //Setting the project values in the configuration that are defined in the external configuration map. + foreach (var configProject in command.Projects) + { + if (configProject == null) continue; + await SetProjectValues(vsActions, configProject, config); + } + } + + return config; // Return the loaded configuration object + } + + /// + /// Configures a project and is associated folders and parameters by applying values from the provided configuration. + /// + /// This method performs the following operations: + /// Loads the project model using the provided and applies + /// configuration values if mappings are defined. Sets parameter values + /// for the project based on the external configuration map. Processes + /// folder configurations, loading folder models and applying configuration values for each mapped + /// folder. Preconditions: must not be . must not be and must have a valid + /// Name. must not be . If any of these preconditions are not met, the method will + /// return without performing any operations. + /// An instance of used to load project and folder models asynchronously. + /// The project configuration containing parameters, folders, and other metadata to be applied. + /// The configuration object to which the values will be applied. + /// Determines if the project value being set is for the exection project. Default value is false. + /// + private static async Task SetProjectValues(IVsActions vsActions, ConfigProject configProject, E config,bool isExecutionProject = false ) + { + // bounds check for null or empty projectMap, configCommand, or config + if (vsActions == null) return; + if (configProject == null) return; + if (config == null) return; + + var parent = configProject.Name; + if (parent == null) return; + + VsProject projectModel = null; + + if (isExecutionProject) + { + var executionProjectMap = _configurationMap.GetExecutionProjectExternalConfigMap(); + + if (executionProjectMap == null) return; + + if(configProject.Name != executionProjectMap.Name) return; + + projectModel = await vsActions.LoadProjectFromConfigProjectAsync(configProject); + + if (projectModel != null && executionProjectMap.SetConfigurationValue != null) + { + var setValue = executionProjectMap.SetConfigurationValue.SetPropertyValue; + setValue.Invoke(config, projectModel); + } + } + else + { + var projectMap = _configurationMap.GetProjectMaps().FirstOrDefault(p => p.Name == parent); + if (projectMap == null) return; + + projectModel = await vsActions.LoadProjectFromConfigProjectAsync(configProject); + + if (projectModel != null & projectMap.SetConfigurationValue != null) + { + var setValue = projectMap.SetConfigurationValue.SetPropertyValue; + setValue.Invoke(config, projectModel); + } + + } + + if(configProject.Parameters != null && configProject.Parameters.Any()) + { + //Setting the parameter values in the confguration that are defined in the external configuration map. + SetParameterValuesForParent(configProject.Parameters, parent, config); + } + + if(configProject.Folders != null && configProject.Folders.Any()) + { + var folderMaps = _configurationMap.GetProjectFolderMaps(parent); + + if (folderMaps.Any()) + { + foreach (var folderMap in folderMaps) + { + if (folderMap == null) continue; + var folderConfig = configProject.Folders.FirstOrDefault(f => f.Name == folderMap.Name); + + if (folderConfig == null) continue; + + var folderModel = await vsActions.LoadProjectFolderFromConfigProjectAsync(configProject, folderConfig); + + if (folderModel != null && folderMap.SetConfigurationValue != null) + { + var setValue = folderMap.SetConfigurationValue.SetPropertyValue; + setValue.Invoke(config, folderModel); + } + } + } + } + } + + /// + /// Sets the configuration parameter values for the specified parent entity by mapping values from the provided + /// source collection to the corresponding properties in the configuration object. + /// + /// This method processes parameters of various types, including dates, strings, + /// booleans, lists, and selected values. For each parameter, it retrieves the corresponding value from the + /// source collection and invokes the appropriate setter on the configuration object. Parameters that do not + /// match the expected types or are not found in the source collection are skipped. + /// A collection of objects representing the source of parameter values. Each + /// parameter in the collection is matched to a configuration property based on its name and type. + /// The name of the parent entity whose parameters are being configured. This value is used to retrieve the + /// relevant parameter mappings. + /// The configuration object of type whose properties will be updated with the + /// parameter values from the source collection. + private static void SetParameterValuesForParent( ObservableCollection source,string parentName, E config) + { + // bounds check for null or empty source, parentName, or config + if (source == null) return; + if (string.IsNullOrEmpty(parentName)) return; + if(config == null) return; + + + var commandParameters = _configurationMap.GetParameters(parentName); + + if (commandParameters.Any()) + { + foreach (var parmData in commandParameters) + { + switch (parmData.ConfigType) + { + case ExternalConfigType.ParameterDate: + if (parmData is ParameterDateExternalConfigMap dateParameter) + { + var dateParameterDetails = source.FirstOrDefault(p => p.Name == dateParameter.Name); + + if (dateParameterDetails != null) + { + var dateValue = dateParameterDetails.LoadDateValueFromConfigParameter(); + + if (dateParameter.SetConfigurationValue != null) + { + var dateSetValue = dateParameter.SetConfigurationValue.SetPropertyValue; + + dateSetValue.Invoke(config, dateValue); + } + } + } + break; + case ExternalConfigType.ParameterString: + + if (parmData is ParameterStringExternalConfigMap stringParameter) + { + + var stringParameterDetails = source.FirstOrDefault(p => p.Name == parmData.Name); + + if(stringParameterDetails != null) + { + var stringValue = stringParameterDetails.LoadStringValueFromConfigParameter(); + if (stringParameter.SetConfigurationValue != null) + { + var stringSetValue = stringParameter.SetConfigurationValue.SetPropertyValue; + stringSetValue.Invoke(config, stringValue); + } + } + } + break; + + case ExternalConfigType.ParameterBool: + + if(parmData is ParameterBoolExternalConfigMap boolParameter) + { + var boolParameterDetails = source.FirstOrDefault(p => p.Name == parmData.Name); + if(boolParameterDetails != null) + { + var boolValue = boolParameterDetails.LoadBoolValueFromConfigParameter(); + if (boolParameter.SetConfigurationValue != null) + { + var boolSetValue = boolParameter.SetConfigurationValue.SetPropertyValue; + boolSetValue.Invoke(config, boolValue); + } + } + } + + break; + + + case ExternalConfigType.ParameterList: + if (parmData is ParameterListExternalConfigMap listParameter) + { + var listParameterDetails = source.FirstOrDefault(p => p.Name == parmData.Name); + if (listParameterDetails != null) + { + var listValues = listParameterDetails.LoadListValueFromConfigParameter(); + if (listParameter.SetConfigurationValue != null) + { + var listSetValue = listParameter.SetConfigurationValue.SetPropertyValue; + listSetValue.Invoke(config, listValues); + } + } + } + + break; + case ExternalConfigType.ParameterSelectedValue: + if (parmData is ParameterSelectedValueExternalConfigMap selectedValueParameter) + { + var selectedValueParameterDetails = source.FirstOrDefault(p => p.Name == parmData.Name); + if (selectedValueParameterDetails != null) + { + var selectedValue = selectedValueParameterDetails.LoadSelectedValueFromConfigParameter(); + if (selectedValueParameter.SetConfigurationValue != null) + { + var selectedValueSetValue = selectedValueParameter.SetConfigurationValue.SetPropertyValue; + selectedValueSetValue.Invoke(config, selectedValue); + } + } + } + break; + + default: + // Skip unsupported parameter types + break; + } + } + } + } + + + + + + + + /// + /// Creates a new instance of based on the current configuration map. + /// + /// This method initializes a by retrieving and processing + /// configuration data from the external configuration map. It includes parameters, execution project details, + /// and associated project configurations. The method throws an exception if the configuration map is not + /// properly loaded. + /// A fully configured instance, including parameters, execution project, and + /// associated project configurations. Null will be returned if the CommandConfig or ExecutionProjectConfig attributes are not assiged to the configuration class. + /// Thrown if the external configuration map is not loaded or cannot provide the necessary data to create the + /// command configuration. + private static ConfigCommand CreateConfigCommand() + { + if (_configurationMap == null) throw new CodeFactoryException($"Could not load the external configuration map for the command type: {commandType}, cannot create the command configuration. "); + + + //Getting the required external configuration map elements if any of these are missing then the command configuration cannot be created, and will return null. + var commandMap = _configurationMap.GetCommandExternalConfigMap(); + + if(commandMap == null) return null; + + //add the execution project to the command configuration. + var executionProjectMap = _configurationMap.GetExecutionProjectExternalConfigMap(); + if (executionProjectMap == null) return null; + + //Process the command configuration map + + var configCommand = commandMap.CreateConfigCommand(); + + //Add paramters to the command configuration. + + var commandParameters = _configurationMap.GetParameters(configCommand.Name); + + if (commandParameters.Any()) + { + foreach (var parmData in commandParameters) + { + var parameterData = parmData.CreateConfigParameter(); + + if(parameterData != null) configCommand.Parameters.Add(parameterData); + } + } + + var executionProjectConfig = CreateExecutionProjectConfig(executionProjectMap); + + configCommand.ExecutionProject = executionProjectConfig; + + var projectMaps = _configurationMap.GetProjectMaps(); + + if (projectMaps.Any()) + { + foreach (var projectMap in projectMaps) + { + var configProject = CreateProjectConfig(projectMap); + if (configProject != null) configCommand.Projects.Add(configProject); + } + + } + + return configCommand; + } + + + + /// + /// Creates a project configuration for execution based on the provided external configuration map. + /// + /// This method initializes a project configuration by loading parameters and folder + /// mappings from the provided external configuration map. Parameters and folders are added to the resulting + /// configuration only if they are defined in the external configuration. + /// The external configuration map that defines the project settings, including parameters and folder mappings. + /// A instance containing the project configuration, including any associated + /// parameters and folders. + private static ConfigProject CreateExecutionProjectConfig(ExecutionProjectExternalConfigMap projectMap) + { + var configProject = projectMap.CreateConfigExecutionProject(); + + //Load the Parameters for the project configuration. + + var projectParameters = _configurationMap.GetParameters(projectMap.Name); + + if (projectParameters.Any()) + { + foreach (var parmData in projectParameters) + { + var parameterData = parmData.CreateConfigParameter(); + if (parameterData != null) configProject.Parameters.Add(parameterData); + } + } + + var projectFolders = _configurationMap.GetProjectFolderMaps(projectMap.Name); + + if (projectFolders.Any()) + { + foreach (var folderMap in projectFolders) + { + var configFolder = folderMap.CreateConfigFolder(); + if (configFolder != null) configProject.Folders.Add(configFolder); + } + } + + return configProject; + } + + /// + /// Creates a project configuration object based on the provided external project configuration map. + /// + /// This method initializes a object using the data from the + /// provided . It populates the configuration with parameters and folder mappings + /// retrieved from the internal configuration map. Only valid parameters and folders are added to the + /// configuration. + /// The external configuration map for the project, which provides the necessary data to create the project + /// configuration. + /// A instance containing the configuration details for the project, including + /// parameters and folder mappings. Returns an empty configuration if no parameters or folders are defined. + private static ConfigProject CreateProjectConfig(ProjectExternalConfigMap projectMap) + { + var configProject = projectMap.CreateConfigProject(); + + //Load the Parameters for the project configuration. + + var projectParameters = _configurationMap.GetParameters(projectMap.Name); + + if (projectParameters.Any()) + { + foreach (var parmData in projectParameters) + { + var parameterData = parmData.CreateConfigParameter(); + if (parameterData != null) configProject.Parameters.Add(parameterData); + } + } + + var projectFolders = _configurationMap.GetProjectFolderMaps(projectMap.Name); + + if (projectFolders.Any()) + { + foreach (var folderMap in projectFolders) + { + var configFolder = folderMap.CreateConfigFolder(); + if (configFolder != null) configProject.Folders.Add(configFolder); + } + } + + return configProject; + } + + + + + /// + /// Loads the external configuration map by analyzing the specified configuration type and its properties. + /// + /// This method inspects the configuration type for attributes that define external + /// configuration mappings. It processes each property of the configuration type to identify and map external + /// configuration details based on the associated attributes. The resulting configuration map is stored as an + /// immutable list. + /// Thrown if the configuration type does not have the required applied, or + /// if a default value for a parameter configuration is invalid (e.g., an invalid date, boolean, or other + /// format). + private static void LoadExternalMap() + { + // Load the type information for the configuration class + Type configType = typeof(E); + + var configClassInfo = configType.GetCustomAttribute() ?? throw new CodeFactoryException($"The command configuration type: {configType.FullName} does not have the required CommandConfigAttribute applied to it, cannot load the external configuration map."); + + var configCommandMap = new CommandExternalConfigMap(configClassInfo.Name, configClassInfo.SupportingCommand.FullName, configClassInfo.Category, configClassInfo.Guidance, configClassInfo.GuidanceUrl); + + var configMap = new List(); + + configMap.Add(configCommandMap); + + var configProperties = configType.GetProperties(); + + + foreach (var configProperty in configProperties) + { + + var externalConfigAttribute = configProperty.GetCustomAttribute(true); + + if (externalConfigAttribute == null) continue; + + var setMethod = configProperty.GetSetMethod(true); + + if (setMethod == null) continue; + + + + switch (externalConfigAttribute.ConfigType) + { + case ExternalConfigType.ExecuteProject: + + var config = externalConfigAttribute as ExecutionProjectConfigAttribute; + + if (config == null) continue; + + var setterExectuionProject = PropertySetter.Init(setMethod); + + var executionProjectConfig = new ExecutionProjectExternalConfigMap(configProperty.Name, config.Guidance, config.GuidanceUrl, setterExectuionProject); + + configMap.Add(executionProjectConfig); + + break; + + case ExternalConfigType.Project: + + var projectConfig = externalConfigAttribute as ProjectConfigAttribute; + + if (projectConfig == null) continue; + + var setterProject = PropertySetter.Init(setMethod); + + var projectExternalConfig = new ProjectExternalConfigMap( configProperty.Name, projectConfig.IsRequired, projectConfig.Guidance, projectConfig.GuidanceUrl, setterProject); + configMap.Add(projectExternalConfig); + break; + + case ExternalConfigType.Folder: + var folderConfig = externalConfigAttribute as ProjectFolderConfigAttribute; + + if (folderConfig == null) continue; + + var setterFolder = PropertySetter.Init(setMethod); + + var folderExternalConfig = new ProjectFolderExternalConfigMap(configProperty.Name, folderConfig.IsRequired, folderConfig.Parent,folderConfig.Path, folderConfig.Guidance, folderConfig.GuidanceUrl, setterFolder); + configMap.Add(folderExternalConfig); + break; + + case ExternalConfigType.ParameterDate: + var parameterDateConfig = externalConfigAttribute as ParameterDateConfigAttribute; + + if (parameterDateConfig == null) continue; + + DateTime? dateDefaultValue = null; + + try + { + dateDefaultValue = parameterDateConfig.DefaultValue != null ? DateTime.Parse(parameterDateConfig.DefaultValue) : null; + } + catch (FormatException ex) + { + throw new CodeFactoryException($"The default value for the parameter date configuration '{configProperty.Name}' is not a valid date format: {parameterDateConfig.DefaultValue}.", ex); + } + + var setterDateParameter = PropertySetter.Init(setMethod); + + var parameterDateExternalConfig = new ParameterDateExternalConfigMap( configProperty.Name, parameterDateConfig.IsRequired, parameterDateConfig.Parent, dateDefaultValue, parameterDateConfig.Guidance, parameterDateConfig.GuidanceUrl, setterDateParameter); + + configMap.Add(parameterDateExternalConfig); + + break; + + case ExternalConfigType.ParameterString: + var parameterStringConfig = externalConfigAttribute as ParameterStringConfigAttribute; + + if (parameterStringConfig == null) continue; + + var setterStringParameter = PropertySetter.Init(setMethod); + + var parameterStringExternalConfig = new ParameterStringExternalConfigMap(configProperty.Name, parameterStringConfig.IsRequired, parameterStringConfig.Parent, parameterStringConfig.DefaultValue, parameterStringConfig.Guidance, parameterStringConfig.GuidanceUrl,setterStringParameter); + + configMap.Add(parameterStringExternalConfig); + + break; + + case ExternalConfigType.ParameterBool: + var parameterBoolConfig = externalConfigAttribute as ParameterBoolConfigAttribute; + + if (parameterBoolConfig == null) continue; + + bool? defaultBoolValue = null; + + try + { + defaultBoolValue = string.IsNullOrEmpty(parameterBoolConfig.DefaultValue) ? null : bool.Parse(parameterBoolConfig.DefaultValue); + } + catch (FormatException ex) + { + throw new CodeFactoryException($"The default value for the parameter boolean configuration '{configProperty.Name}' is not a valid boolean format: {parameterBoolConfig.DefaultValue}.", ex); + } + + var setterBoolParameter = PropertySetter.Init(setMethod); + + var parameterBoolExternalConfig = new ParameterBoolExternalConfigMap(configProperty.Name, parameterBoolConfig.IsRequired, parameterBoolConfig.Parent, defaultBoolValue, parameterBoolConfig.Guidance, parameterBoolConfig.GuidanceUrl, setterBoolParameter); + configMap.Add(parameterBoolExternalConfig); + break; + + case ExternalConfigType.ParameterList: + var parameterListConfig = externalConfigAttribute as ParameterListConfigAttribute; + + if (parameterListConfig == null) continue; + + var listAttributes = configProperty.GetCustomAttributes(false).ToList(); + + List defaultListValues = listAttributes.Any() ? new List() : null; + + + if (listAttributes.Any()) + { + foreach (var listAttribute in listAttributes) + { + defaultListValues.Add(listAttribute.ListValue); + } + } + + var setterListParameter = PropertySetter>.Init(setMethod); + var parameterListExternalConfig = new ParameterListExternalConfigMap(configProperty.Name, parameterListConfig.IsRequired, parameterListConfig.Parent, defaultListValues, parameterListConfig.Guidance, parameterListConfig.GuidanceUrl, setterListParameter); + configMap.Add(parameterListExternalConfig); + break; + + case ExternalConfigType.ParameterSelectedValue: + var parameterSelectedValueConfig = externalConfigAttribute as ParameterSelectedValueConfigAttribute; + + if (parameterSelectedValueConfig == null) continue; + + var selectionValuesAttributes = configProperty.GetCustomAttributes(false).ToList(); + + List selectionValues = selectionValuesAttributes.Any() ? new List() : null; + + if (selectionValuesAttributes.Any()) + { + foreach (var selectionValueAttribute in selectionValuesAttributes) + { + selectionValues.Add(selectionValueAttribute.ListValue); + } + } + + var setterSelectedValueParameter = PropertySetter.Init(setMethod); + var parameterSelectedValueExternalConfig = new ParameterSelectedValueExternalConfigMap(configProperty.Name, parameterSelectedValueConfig.IsRequired, parameterSelectedValueConfig.Parent, parameterSelectedValueConfig.DefaultValue, selectionValues, parameterSelectedValueConfig.Guidance, parameterSelectedValueConfig.GuidanceUrl, setterSelectedValueParameter); + configMap.Add(parameterSelectedValueExternalConfig); + break; + } + + } + + _configurationMap = configMap.ToImmutableList(); + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigAttribute.cs new file mode 100644 index 0000000..ba422c5 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigAttribute.cs @@ -0,0 +1,35 @@ +using CodeFactory.WinVs.Commands; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Serves as a base class for attributes that specify external configuration types. + /// + /// This attribute is intended to be used as a base for defining custom attributes that represent + /// specific types of external configurations. Derived classes should specify the configuration type through the + /// constructor. + public abstract class ExternalConfigAttribute : Attribute + { + + /// + /// Initializes a new instance of the class with the specified + /// configuration type. + /// + /// The type of external configuration to associate with this attribute. + protected ExternalConfigAttribute(ExternalConfigType configType) + { + ConfigType = configType; + } + + /// + /// Gets the type of external configuration this attribute represents. + /// + + public ExternalConfigType ConfigType { get; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigExtensions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigExtensions.cs new file mode 100644 index 0000000..c93ae67 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigExtensions.cs @@ -0,0 +1,370 @@ +using CodeFactory.WinVs.Factory; +using CodeFactory.WinVs.Models.ProjectSystem; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Provides extension methods for loading and validating configuration parameters and project-related data in the + /// context of Visual Studio automation. + /// + /// This static class contains methods to assist with loading configuration parameters, project + /// folders, and Visual Studio projects based on provided configuration objects. It ensures proper validation of + /// required parameters and provides meaningful exception messages for error scenarios. + public static class ExternalConfigExtensions + { + + /// + /// Asynchronously loads a project folder based on the provided configuration settings. + /// + /// This method validates the provided configuration and ensures that required folders + /// are properly loaded. If the folder is not required and its path is not defined, the method returns . + /// The type used to provide context in exception messages. Typically, this represents the calling class or + /// context. + /// The instance used to perform Visual Studio automation actions. Cannot be . + /// The project configuration that specifies the project to which the folder belongs. Cannot be . + /// The folder configuration that specifies the folder to load. Cannot be . + /// The name of the calling member, automatically provided by the compiler. Used for context in exception + /// messages. + /// A representing the loaded project folder, or if the + /// folder is not required and its path is not defined in the configuration. + /// Thrown if: is . is . is . The folder path is not defined in the + /// configuration and the folder is marked as required. The folder could + /// not be loaded and it is marked as required. + public static async Task LoadProjectFolderFromConfigProjectAsync(this IVsActions source, ConfigProject project, ConfigFolder folder, [CallerMemberName] string callerName = null) + { + //The factory request name is used to provide context in exception messages. + string requestName = typeof(T).Name; + + // Validate the source parameter to ensure it is not null. + if (source == null) + throw new CodeFactoryException(ExceptionMessages.NoAutomationService(callerName)); + + // Validate the project parameter to ensure it is not null. + if (project == null) + throw new CodeFactoryException(ExceptionMessages.LoadProjectConfigurationFailed(requestName, callerName)); + + // Validate the folder parameter to ensure it is not null. + if (folder == null) + throw new CodeFactoryException(ExceptionMessages.LoadFolderConfigurationFailed(requestName, callerName)); + + var isRequired = folder?.Required ?? false; + + var folderPath = folder?.Path; + + if (string.IsNullOrEmpty(folderPath)) + { + if (isRequired) + { + // If the folder path is not defined in the configuration, throw an exception. + throw new CodeFactoryException(ExceptionMessages.LoadRequiredProjectFolderFailed(folder?.Name, requestName, callerName)); + } + else + { + // If the folder is not required, return null. + return null; + } + + } + // Extract the folder path and name from the source configuration. + VsProjectFolder projectFolder = await source.GetProjectFolderFromConfigAsync(project, folderPath, true); + + if (projectFolder == null & isRequired) + { + throw new CodeFactoryException(ExceptionMessages.LoadRequiredProjectFolderFailed(folder?.Name, requestName, callerName)); + } + + return projectFolder; + } + + + /// + /// Asynchronously loads a Visual Studio project based on the provided configuration. + /// + /// This method uses the provided configuration to locate and load a Visual Studio + /// project. If the project is marked as required and cannot be found, an exception is thrown. Otherwise, the + /// method returns for non-required projects that cannot be loaded. + /// The type used to provide context for exception messages. Typically represents the caller's type. + /// The instance used to perform Visual Studio automation actions. Cannot be . + /// The configuration object that specifies the project to load. Cannot be . + /// The name of the calling member, automatically provided by the compiler. Used for context in exception + /// messages. Optional. + /// A task that represents the asynchronous operation. The task result contains the loaded instance, or if the project is not required and could not be + /// found. + /// Thrown if is . Thrown if is . Thrown if the project could not be loaded and it is marked as required in the + /// configuration. + public static async Task LoadProjectFromConfigProjectAsync(this IVsActions source, ConfigProject project, [CallerMemberName] string callerName = null) + { + //The factory request name is used to provide context in exception messages. + string requestName = typeof(T).Name; + + // Validate the source parameter to ensure it is not null. + if (source == null) + throw new CodeFactoryException(ExceptionMessages.NoAutomationService(callerName)); + + // Validate the project parameter to ensure it is not null. + if (project == null) + throw new CodeFactoryException(ExceptionMessages.LoadProjectConfigurationFailed(requestName, callerName)); + + var projectParameterName = project?.ProjectName; + + var isRequired = project?.Required ?? false; + + var projectModel = await source.GetProjectFromConfigAsync(project); + + if (projectModel == null & isRequired) throw new CodeFactoryException(ExceptionMessages.LoadRequiredProjectFailed(projectParameterName, requestName, callerName)); + + return projectModel; + } + + /// + /// Loads the string value of a configuration parameter, validating its presence and requirements. + /// + /// This method ensures that required parameters have a valid string value. If the + /// parameter is not required and its value is null or empty, the method will return + /// instead of throwing an exception. + /// The type of the factory request, used to provide context in exception messages. Must implement . + /// The configuration parameter to load the value Tom. Cannot be . + /// The name of the calling member, automatically provided by the compiler if not explicitly specified. Used + /// for context in exception messages. + /// The string value of the configuration parameter. Returns if the parameter is not + /// required and its value is null or empty. + /// Thrown if is or if the parameter is required but its value + /// is null or empty. + public static string LoadStringValueFromConfigParameter(this ConfigParameter source, [CallerMemberName] string callerName = null) + { + //The factory request name is used to provide context in exception messages. + string requestName = typeof(T).Name; + if (source == null) + throw new CodeFactoryException(ExceptionMessages.LoadParameterConfigurationFailed(requestName, callerName)); + + // Validate the source parameter to ensure it is not null. + var parameterValue = source?.Value?.StringValue; + + // the parameter name is used to provide context in exception messages. + var parameterName = source?.Name; + + // If the parameter value is null or empty, we need to check if it is required. + bool isRequired = source?.Required ?? false; + + if (string.IsNullOrEmpty(parameterValue)) + { + if (isRequired) + { + // If the parameter is required and the value is null or empty, throw an exception. + throw new CodeFactoryException(ExceptionMessages.LoadRequiredStringParameterFailed(parameterName, requestName, callerName)); + } + else + { + // If the parameter is not required, return null. + return null; + } + } + return parameterValue; + } + + /// + /// Loads the boolean value of a configuration parameter, validating its presence and requirements. + /// + /// This method ensures that the configuration parameter is properly validated. If the + /// parameter is required and its value is missing, an exception is thrown. If the parameter is not required and + /// its value is missing, the method returns . + /// The type of the factory request that provides context for exception messages. Must implement . + /// The configuration parameter to load the boolean value Tom. Cannot be . + /// The name of the calling member, automatically provided by the compiler. Used for context in exception + /// messages. + /// The boolean value of the configuration parameter if it is present; if the parameter + /// is not required and its value is missing. + /// Thrown if is or if the parameter is required but its value + /// is missing. + public static bool? LoadBoolValueFromConfigParameter(this ConfigParameter source, [CallerMemberName] string callerName = null) + { + //The factory request name is used to provide context in exception messages. + string requestName = typeof(T).Name; + + // Validate the source parameter to ensure it is not null. + if (source == null) + throw new CodeFactoryException(ExceptionMessages.LoadParameterConfigurationFailed(requestName, callerName)); + + // Validate the source parameter to ensure it is not null. + var parameterValue = source?.Value?.BoolValue; + + // the parameter name is used to provide context in exception messages. + var parameterName = source?.Name; + + // If the parameter value is null or empty, we need to check if it is required. + bool isRequired = source?.Required ?? false; + + if (!parameterValue.HasValue) + { + if (isRequired) + { + // If the parameter is required and the value is null or empty, throw an exception. + throw new CodeFactoryException(ExceptionMessages.LoadRequiredBoolParameterFailed(parameterName, requestName, callerName)); + } + else + { + // If the parameter is not required, return false. + return null; + } + } + return parameterValue.Value; + } + + /// + /// Loads a date parameter value Tom the specified instance. + /// + /// This method validates the provided instance and ensures + /// that required parameters have a value. If the parameter is not required and no value is provided, the method + /// returns . + /// The type of the factory request, which must implement . This is used to + /// provide context in exception messages. + /// The instance Tom which to load the date parameter value. Cannot be . + /// The name of the calling member. This is automatically provided by the compiler if not explicitly specified. + /// Used to provide context in exception messages. + /// The value of the parameter if it is present; otherwise, if the + /// parameter is not required and no value is provided. + /// Thrown if is or if the parameter is required but no value + /// is provided. + public static DateTime? LoadDateValueFromConfigParameter(this ConfigParameter source, [CallerMemberName] string callerName = null) + { + //The factory request name is used to provide context in exception messages. + string requestName = typeof(T).Name; + + // Validate the source parameter to ensure it is not null. + if (source == null) + throw new CodeFactoryException(ExceptionMessages.LoadParameterConfigurationFailed(requestName, callerName)); + + // Validate the source parameter to ensure it is not null. + var parameterValue = source?.Value?.DateTimeValue; + + // the parameter name is used to provide context in exception messages. + var parameterName = source?.Name; + + bool isRequired = source?.Required ?? false; + if (!parameterValue.HasValue) + { + if (isRequired) + { + throw new CodeFactoryException(ExceptionMessages.LoadRequiredDateParameterFailed(parameterName, requestName, callerName)); + } + else + { + // If the parameter is not required, return null. + return null; + } + } + + return parameterValue.Value; + } + + /// + /// Loads the list parameter value from the specified source. + /// + /// This method validates the provided and ensures that the + /// parameter value is properly loaded. If the parameter is required and no values are present, an exception is + /// thrown. Otherwise, an empty list is returned. + /// The type of the factory request, which must implement . This type is used + /// to provide context in exception messages. + /// The instance Tom which to load the list parameter value. Cannot be . + /// The name of the calling member. This is automatically populated by the compiler if not explicitly provided. + /// Used to provide context in exception messages. + /// A read-only list of objects representing the parameter value. If the + /// parameter is not required and no values are present, an empty list is returned. + /// Thrown if is or if the parameter is required but no values + /// are present. + public static IReadOnlyList LoadListValueFromConfigParameter(this ConfigParameter source, [CallerMemberName] string callerName = null) + { + //The factory request name is used to provide context in exception messages. + string requestName = typeof(T).Name; + // Validate the source parameter to ensure it is not null. + if (source == null) + throw new CodeFactoryException(ExceptionMessages.LoadParameterConfigurationFailed(requestName, callerName)); + // Validate the source parameter to ensure it is not null. + var parameterValue = source?.Value?.ListValue; + // the parameter name is used to provide context in exception messages. + var parameterName = source?.Name; + bool isRequired = source?.Required ?? false; + if (parameterValue == null || parameterValue.Count == 0) + { + if (isRequired) + { + throw new CodeFactoryException(ExceptionMessages.LoadRequiredListParameterFailed(parameterName, requestName, callerName)); + } + else + { + // If the parameter is not required, return an empty list. + return ImmutableList.Empty; + } + } + + return parameterValue.Select(pv => pv.ListValue).ToImmutableList(); + } + + /// + /// Retrieves the selected value of a configuration parameter, validating its presence if required. + /// + /// This method ensures that the selected value of the configuration parameter is + /// retrieved safely. If the parameter is required and no value is set, an exception is thrown. + /// The type of the factory request, which provides context for exception messages. Must implement . + /// The configuration parameter Tom which the selected value is retrieved. Cannot be . + /// The name of the calling member, automatically provided by the compiler if not explicitly specified. Used for + /// context in exception messages. + /// The selected value of the configuration parameter, or if the parameter is not + /// required and no value is set. + /// Thrown if is or if the parameter is required but no value + /// is set. + public static string LoadSelectedValueFromConfigParameter(this ConfigParameter source, [CallerMemberName] string callerName = null) + { + //The factory request name is used to provide context in exception messages. + string requestName = typeof(T).Name; + // Validate the source parameter to ensure it is not null. + if (source == null) + throw new CodeFactoryException(ExceptionMessages.LoadParameterConfigurationFailed(requestName, callerName)); + // Validate the source parameter to ensure it is not null. + var parameterValue = source?.Value?.SelectedValue?.SelectedValue; + + // the parameter name is used to provide context in exception messages. + var parameterName = source?.Name; + + // determine if the parameter is required + bool isRequired = source?.Required ?? false; + + // If the parameter value is null or empty, we need to check if it is required. + if (string.IsNullOrEmpty(parameterValue)) + { + if (isRequired) + { + throw new CodeFactoryException(ExceptionMessages.LoadRequiredSelectedValueParameterFailed(parameterName, requestName, callerName)); + } + else + { + // If the parameter is not required, return null. + return null; + } + } + return parameterValue; + } + } +} + diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigMap.cs new file mode 100644 index 0000000..e571c4a --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigMap.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Abstraction used by all external configuration mapped data. + /// + public abstract class ExternalConfigMap + { + + /// + /// Initializes a new instance of the class, which represents a mapping for an + /// external configuration value. + /// + /// This constructor is typically used to define mappings for external configuration + /// values, including their metadata and how they should be applied to a target object. + /// The type of the external configuration, indicating its category or purpose. + /// The name of the configuration value. This cannot be null or empty. + /// A value indicating whether the configuration value is required. if the value is + /// required; otherwise, . + /// Guidance or description for the configuration value, providing additional context or instructions. + /// A URL pointing to detailed guidance or documentation for the configuration value. This can be null if no URL + /// is provided. + /// An action delegate used to set the configuration value. The first parameter represents the target object, + /// and the second parameter represents the value to set. + protected ExternalConfigMap( ExternalConfigType configType, string name, bool isRequired, string guidance, string guidanceUrl, IPropertySetter setConfigurationValue) + { + Name = name; + ConfigType = configType; + IsRequired = isRequired; + Guidance = guidance; + GuidanceUrl = guidanceUrl; + SetConfigurationValue = setConfigurationValue; + } + + /// + /// Gets the name of the external configuration item. + /// + public string Name { get; init; } + + /// + /// Gets the type of external configuration used by the system. + /// + public ExternalConfigType ConfigType { get; init; } + + /// + /// Flag that determines if the configuration is required in order for the automation to run. + /// + public bool IsRequired { get; init; } + + /// + /// Help documentation so the user understands what to do with the configuration. + /// + public string Guidance { get; init; } + + /// + /// Fully qualified URL where the user can click to see more detailed guidance about the parameter. + /// + public string GuidanceUrl { get; init; } + + /// + /// Gets an action that sets a configuration value for a specified property. + /// + public IPropertySetter SetConfigurationValue { get; init; } + + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigMapExtensions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigMapExtensions.cs new file mode 100644 index 0000000..11c3ecd --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigMapExtensions.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Extension methods for working with external configuration maps in the context of a commands configuration. + /// + public static class ExternalConfigMapExtensions + { + /// + /// Extension method that retrieves the external configuration map for a specified command type from the provided list of + /// configuration maps. + /// + /// The list of external configuration maps to search. Cannot be . + /// The name of the command type to locate within the configuration maps. + /// The corresponding to the specified command type, or if no matching configuration map is found. + /// Thrown if is . + public static CommandExternalConfigMap GetCommandExternalConfigMap(this ImmutableList source) + { + if (source is null) + throw new CodeFactoryException("No configuration maps were found. Cannot load command data."); + + return source.FirstOrDefault(map => map.ConfigType == ExternalConfigType.Command) as CommandExternalConfigMap; + } + + /// + /// Extension method that retrieves the external configuration map of type from + /// the provided list of external configuration maps. + /// + /// The list of external configuration maps to search. Cannot be . + /// An instance of if a matching configuration map is found; + /// otherwise, . + /// Thrown if is . + public static ExecutionProjectExternalConfigMap GetExecutionProjectExternalConfigMap(this ImmutableList source) + { + if (source is null) + throw new CodeFactoryException("No configuration maps were found. Cannot load execution project data."); + return source.FirstOrDefault(map => map.ConfigType == ExternalConfigType.ExecuteProject) as ExecutionProjectExternalConfigMap; + } + + /// + /// Extension method that retrieves a list of project-specific configuration maps from the provided collection of external + /// configuration maps. + /// + /// The collection of external configuration maps to filter. Cannot be . + /// A list of objects representing project-specific configurations. + /// Returns an empty list if no project-specific configurations are found. + /// Thrown if is . + public static List GetProjectMaps(this ImmutableList source) + { + if (source is null) + throw new CodeFactoryException("No configuration maps were found. Cannot load project data."); + + return source.Where(map => map.ConfigType == ExternalConfigType.Project).Cast().ToList(); + + + } + + /// + /// Extension method that retrieves a list of project folder configuration maps from the specified source, filtered by the provided + /// parent identifier. + /// + /// The collection of external configuration maps to search. Cannot be . + /// The parent identifier used to filter the configuration maps. Cannot be or empty. + /// A list of objects that match the specified parent identifier. + /// Returns an empty list if no matches are found. + /// Thrown if is or if is or empty. + public static List GetProjectFolderMaps(this ImmutableList source, string parent) + { + if (source is null) + throw new CodeFactoryException("No configuration maps were found. Cannot load folder data."); + + if (string.IsNullOrEmpty(parent)) throw new CodeFactoryException("The parent cannot be null or empty. Cannot load project folder configuration maps."); + + return source.Where(map => map.ConfigType == ExternalConfigType.Folder).Cast().Where(map => map.Parent == parent).ToList(); + + } + + /// + /// Retrieves a list of configuration maps that contain parameters from the source collection that match the specified parent + /// identifier. + /// + /// The collection of objects to search. Cannot be null. + /// The identifier of the parent to match. Cannot be null or empty. + /// A list of objects where the Parent property matches the specified + /// value. Returns an empty list if no matches are found. + /// Thrown if is null or if is null or empty. + public static List GetParameters(this ImmutableList source, string parent) + { + if (source is null) + throw new CodeFactoryException("No configuration maps were found. Cannot load parameter data."); + + if (string.IsNullOrEmpty(parent)) throw new CodeFactoryException("The parent cannot be null or empty. Cannot load parameter configuration maps."); + + var result = new List(); + + foreach (var item in source) + { + switch (item.ConfigType) + { + case ExternalConfigType.ParameterBool: + + var boolParm = item as ParameterBoolExternalConfigMap; + + if(boolParm?.Parent == parent) result.Add(item); + + break; + + case ExternalConfigType.ParameterString: + + var stringParm = item as ParameterStringExternalConfigMap; + + if(stringParm?.Parent == parent) result.Add(item); + + break; + + case ExternalConfigType.ParameterDate: + + var dateParm = item as ParameterDateExternalConfigMap; + + if(dateParm?.Parent == parent) result.Add(item); + + break; + + case ExternalConfigType.ParameterList: + + var listParm = item as ParameterListExternalConfigMap; + + if(listParm?.Parent == parent) result.Add(item); + + break; + + case ExternalConfigType.ParameterSelectedValue: + + var selectedValueParm = item as ParameterSelectedValueExternalConfigMap; + + if(selectedValueParm?.Parent == parent) result.Add(item); + + + break; + + default: + + break; + } + + } + + return result; + } + + /// + /// Creates a instance based on the provided + /// source. + /// + /// The external configuration map used to create the . Must not be . + /// A instance corresponding to the type of the provided . + /// Thrown if is or if the type of is + /// not supported for creating a . + public static ConfigParameter CreateConfigParameter(this ExternalConfigMap source) + { + if (source is null) + throw new CodeFactoryException("The source parameter information cannot be null. Cannot load the parameter configuration"); + return source switch + { + ParameterBoolExternalConfigMap boolParm => boolParm.CreateConfigParameter(), + ParameterStringExternalConfigMap stringParm => stringParm.CreateConfigParameter(), + ParameterDateExternalConfigMap dateParm => dateParm.CreateConfigParameter(), + ParameterListExternalConfigMap listParm => listParm.CreateConfigParameter(), + ParameterSelectedValueExternalConfigMap selectedValueParm => selectedValueParm.CreateConfigParameter(), + _ => throw new CodeFactoryException($"The provided external configuration map type '{source.ConfigType}' is not supported for creating a ConfigParameter.") + }; + } + + /// + /// Extension method that creates a new instance based on the provided . + /// + /// The source configuration map used to populate the properties. Cannot be . + /// A new instance initialized with the values from the . + /// Thrown if is . + public static ConfigCommand CreateConfigCommand(this CommandExternalConfigMap source) + { + if (source is null) + throw new CodeFactoryException("The source command information cannot be null. Cannot load the command configuration"); + return new ConfigCommand + { + Name = source.Name, + Category = source.Category, + CommandType = source.CommandType, + Guidance = source.Guidance, + GuidanceUrl = source.GuidanceUrl + }; + } + + /// + /// Extension method that loads a from the provided source. + /// + /// Map to transform + /// Loaded ConfigProject + /// Raised if the provided map is null. + public static ConfigProject CreateConfigExecutionProject(this ExecutionProjectExternalConfigMap source) + { + + if (source is null) + throw new CodeFactoryException("The source project information cannot be null. Cannot load the project configuration"); + + return new ConfigProject { Name = source.Name, Required = true, Guidance = source.Guidance, GuidanceUrl = source.GuidanceUrl }; + + } + + /// + /// Extension method that loads a from the provided source. + /// + /// Map to transform + /// Loaded ConfigProject + /// Raised if the provided map is null. + public static ConfigProject CreateConfigProject(this ProjectExternalConfigMap source) + { + + if (source is null) + throw new CodeFactoryException("The source project information cannot be null. Cannot load the project configuration"); + + return new ConfigProject { Name = source.Name, Required = source.IsRequired, Guidance = source.Guidance, GuidanceUrl = source.GuidanceUrl }; + + } + + /// + /// Extension methoid that creates a new instance based on the provided . + /// + /// The source containing the configuration data. Cannot be . + /// A instance populated with the data from the . + /// Thrown if is . + public static ConfigFolder CreateConfigFolder(this ProjectFolderExternalConfigMap source) + { + if (source is null) + throw new CodeFactoryException("The source project folder information cannot be null. Cannot load the project folder configuration"); + + return new ConfigFolder { Name = source.Name, Required = source.IsRequired, Guidance = source.Guidance, GuidanceUrl = source.GuidanceUrl, Path = source.Path }; + } + + /// + /// Extension method that creates a new instance based on the provided source. + /// + /// The returned includes the name, required status, + /// guidance, and guidance URL from the source. Additionally, it initializes the property with a selected value and a collection of selection values derived + /// from the source's selection values. If the source contains no selection values, the collection will be + /// empty. + /// The containing the configuration data used to create + /// the . + /// A instance populated with the values from the . + /// Thrown if the is . + public static ConfigParameter CreateConfigParameter(this ParameterSelectedValueExternalConfigMap source) + { + if (source is null) + throw new CodeFactoryException("The source parameter information cannot be null. Cannot load the parameter configuration"); + + ObservableCollection selectionValues = source.SelectionValues.Any() + ? new ObservableCollection(source.SelectionValues.Select(sv => new ConfigParameterListValue { ListValue = sv })) + : new ObservableCollection(); + + return new ConfigParameter + { + Name = source.Name, + Required = source.IsRequired, + Guidance = source.Guidance, + GuidanceUrl = source.GuidanceUrl, + Value = new ConfigParameterValue + { + ValueType = ConfigParameterValueType.SelectedValue, + SelectedValue = new ConfigParameterSelectedValue { SelectedValue = source.DefaultValue, SelectionValues = selectionValues } + } + }; + + } + + /// + /// Extension method that creates a new instance based on the provided source. + /// + /// The source containing the configuration details. Cannot be . + /// A instance initialized with the values from the . + /// Thrown if the is . + public static ConfigParameter CreateConfigParameter(this ParameterBoolExternalConfigMap source) + { + if (source is null) + throw new CodeFactoryException("The source parameter information cannot be null. Cannot load the parameter configuration"); + return new ConfigParameter + { + Name = source.Name, + Required = source.IsRequired, + Guidance = source.Guidance, + GuidanceUrl = source.GuidanceUrl, + Value = new ConfigParameterValue + { + ValueType = ConfigParameterValueType.Boolean, + BoolValue = source.DefaultValue + } + }; + } + + /// + /// Extension method that creates a new instance based on the provided source. + /// + /// The returned will have its property set to a list-based value type (). If the contains default values, they will + /// be included in the collection; otherwise, the collection will + /// be empty. + /// The source containing the configuration data. Must not be . + /// A instance populated with the data from the . + /// Thrown if the is . + public static ConfigParameter CreateConfigParameter(this ParameterListExternalConfigMap source) + { + if (source is null) + throw new CodeFactoryException("The source parameter information cannot be null. Cannot load the parameter configuration"); + + + ObservableCollection defaultValues = source.DefaultValue.Any() + ? new ObservableCollection(source.DefaultValue.Select(sv => new ConfigParameterListValue { ListValue = sv })) + : new ObservableCollection(); + + return new ConfigParameter + { + Name = source.Name, + Required = source.IsRequired, + Guidance = source.Guidance, + GuidanceUrl = source.GuidanceUrl, + Value = new ConfigParameterValue + { + ValueType = ConfigParameterValueType.List, + ListValue = defaultValues + } + }; + } + + /// + /// Extension method that creates a new instance based on the provided source. + /// + /// The source configuration map containing parameter details. Cannot be . + /// A object initialized with the values from the . + /// Thrown if is . + public static ConfigParameter CreateConfigParameter(this ParameterStringExternalConfigMap source) + { + if (source is null) + throw new CodeFactoryException("The source parameter information cannot be null. Cannot load the parameter configuration"); + return new ConfigParameter + { + Name = source.Name, + Required = source.IsRequired, + Guidance = source.Guidance, + GuidanceUrl = source.GuidanceUrl, + Value = new ConfigParameterValue + { + ValueType = ConfigParameterValueType.String, + StringValue = source.DefaultValue + } + }; + } + + /// + /// Extension method that creates a new instance based on the provided source. + /// + /// The source containing the configuration data. Must not be . + /// A instance initialized with the values from the . + /// Thrown if the is . + public static ConfigParameter CreateConfigParameter(this ParameterDateExternalConfigMap source) + { + if (source is null) + throw new CodeFactoryException("The source parameter information cannot be null. Cannot load the parameter configuration"); + return new ConfigParameter + { + Name = source.Name, + Required = source.IsRequired, + Guidance = source.Guidance, + GuidanceUrl = source.GuidanceUrl, + Value = new ConfigParameterValue + { + ValueType = ConfigParameterValueType.DateTime, + DateTimeValue = source.DefaultValue + } + }; + } + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigType.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigType.cs new file mode 100644 index 0000000..2549a05 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalConfigType.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies the type of external configuration used to load a CodeFactory commands configuration. + /// + /// This enumeration defines various categories of external configurations, such as commands, + /// projects, folders, and parameters. It is typically used to identify and handle different types of external + /// inputs or settings in a structured manner. + public enum ExternalConfigType + { + /// + /// Represents the command configuration for a CodeFactory command. + /// + Command = 0, + + /// + /// Represents the project where a command is executed from. + /// + ExecuteProject = 1, + + /// + /// Represents a project folder where a command is executed from. + /// + ExecuteProjectFolder = 2, + + /// + /// Represents a project used by the CodeFactory command. + /// + Project = 3, + + /// + /// Represents a project folder used by the CodeFactory command. + /// + Folder = 4, + + /// + /// Represents a parameter string value that is used by the CodeFactory command. + /// + ParameterString =5, + + /// + /// Represents a parameter that specifies a date that is used by the CodeFactory command. + /// + ParameterDate = 6, + + /// + /// Represents a parameter type that is a boolean value that is used by the CodeFactory command. + /// + ParameterBool = 7, + + /// + /// Represents a parameter that holds a list of string values that is used by the CodeFactory command. + /// + ParameterList = 8, + + /// + /// Represents a parameter that the user selects a value from the list of values. + /// + ParameterSelectedValue = 9 + + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalProjectFolderConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalProjectFolderConfigMap.cs new file mode 100644 index 0000000..ad0faef --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ExternalProjectFolderConfigMap.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// + /// + public class ExternalProjectFolderConfigMap: ExternalConfigMap + { + /// + /// Initializes a new instance of the class with the specified name, path, and optional guidance and guidance URL. + /// + /// The name of the project folder configuration. + /// The name of the parent project that hosts this project. + /// The relative path to the project folder. + /// Flag that determines if the folder is required in the execution of the command. + /// Optional guidance text for the project folder configuration. + /// Optional URL for additional guidance or documentation. + /// An action delegate used to set the configuration value. The first parameter represents the target object, + /// and the second parameter represents the value to set. + public ExternalProjectFolderConfigMap(string name, string parent, string path,bool isRequired, string guidance, string guidanceUrl, IPropertySetter setConfigurationValue) + : base(ExternalConfigType.Folder, name, isRequired, guidance, guidanceUrl,setConfigurationValue) + { + Path = path; + Parent = parent; + } + + /// + /// Gets or sets the relative path to the project folder. + /// + public string Path { get; set; } + + /// + /// The parent project that hosts this project folder configuration. + /// + public string Parent { get; set; } + } + +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/IPropertySetter.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/IPropertySetter.cs new file mode 100644 index 0000000..78c1b26 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/IPropertySetter.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Defines a mechanism for setting properties on an object. + /// + /// This interface is intended to be implemented by classes that provide functionality for + /// modifying or assigning values to properties of an object. The specific behavior and usage depend on the + /// implementing class. + public interface IPropertySetter + { + + /// + /// Sets the value of a specified property on the target class. + /// + /// Target class to set the property on + /// The value of the property to be set. + void SetPropertyValue(object targetClass, object propertyValue); + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ListValueConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ListValueConfigAttribute.cs new file mode 100644 index 0000000..34bc996 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ListValueConfigAttribute.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies a value associated with a property that represents a list item. + /// + /// This attribute can be applied to properties to associate them with a specific value in a + /// list. It supports multiple instances on the same property. + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)] + public class ListValueConfigAttribute:Attribute + { + /// + /// The value of the list item that this attribute is associated with. + /// + public string ListValue { get; init; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterBoolConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterBoolConfigAttribute.cs new file mode 100644 index 0000000..8e86e41 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterBoolConfigAttribute.cs @@ -0,0 +1,57 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies metadata for a boolean parameter used in automation configurations. + /// + /// This attribute is applied to properties to define additional metadata for boolean parameters, + /// such as whether the parameter is required, its default value, and any guidance or documentation associated with + /// its usage. It is intended to facilitate the configuration and validation of automation processes. + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class ParameterBoolConfigAttribute:ExternalConfigAttribute + { + + /// + /// Initializes a new instance of the class. + /// + /// This attribute is used to specify that the associated member represents a boolean + /// parameter in an external configuration of type . + public ParameterBoolConfigAttribute(): base(ExternalConfigType.ParameterBool) + { + // Intentionally left blank, this is used to define the type of external configuration this attribute represents. + } + + + /// + /// The name of the commmand, project, or project folder that this parameter bool is associated with. + /// + public string Parent { get; set; } + + /// + /// Flag that determines if the parameter bool is required in order for the automation to run. + /// + public bool IsRequired { get; set; } = false; + + /// + /// Gets or sets the guidance text that provides instructions for using the parameter bool configuration. + /// + public string Guidance { get; set; } + + /// + /// Gets or sets the URL that provides additional guidance or documentation. + /// + public string GuidanceUrl { get; set; } + + /// + /// The default value for the parameter bool configuration. This can be used to provide a pre-defined value that will be used if no other value is specified. + /// + public string DefaultValue { get; set; } = null; + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterBoolExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterBoolExternalConfigMap.cs new file mode 100644 index 0000000..39002ce --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterBoolExternalConfigMap.cs @@ -0,0 +1,50 @@ +using CodeFactory.WinVs.Commands; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Represents a configuration mapping for a boolean parameter, including metadata such as its name, default value, + /// and associated parent configuration group or section. + /// + /// This class is used to define and manage boolean parameters in an external configuration + /// system. It provides metadata such as the parameter's name, whether it is required, its default value, and + /// additional guidance or documentation links. The configuration value can be set using the provided + /// delegate. + public class ParameterBoolExternalConfigMap : ExternalConfigMap + { + /// + /// Initializes a new instance of the class with the specified + /// configuration details. + /// + /// The name of the parameter. This value cannot be null or empty. + /// A value indicating whether the parameter is required. if the parameter is required; + /// otherwise, . + /// The name of the parent configuration group or section to which this parameter belongs. + /// The default value of the parameter if no value is explicitly provided. + /// Guidance or description for the parameter, providing additional context or usage information. + /// A URL pointing to external documentation or guidance for the parameter. This value can be null if no + /// external guidance is available. + /// An action delegate used to set the configuration value for this parameter. The first parameter represents + /// the target object, and the second parameter represents the value to set. + public ParameterBoolExternalConfigMap(string name, bool isRequired, string parent, bool? defaultValue, string guidance, string guidanceUrl, IPropertySetter setConfigurationValue) : base( ExternalConfigType.ParameterBool, name, isRequired, guidance, guidanceUrl, setConfigurationValue) + { + Parent = parent; + DefaultValue = defaultValue; + } + + /// + /// The name of the commmand, project, or project folder that this parameter string is associated with. + /// + public string Parent { get; init; } + + /// + /// The default value for the parameter bool configuration. This can be used to provide a pre-defined value that will be used if no other value is specified. + /// + public bool? DefaultValue { get; init; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterDateConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterDateConfigAttribute.cs new file mode 100644 index 0000000..362d7ee --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterDateConfigAttribute.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies metadata for a parameter date configuration, including its parent association, whether it is + /// required, and additional guidance or default values. + /// + /// This attribute is intended to be applied to properties to define metadata for parameter date + /// configurations in automation scenarios. It allows specifying the parent context, whether the parameter is + /// required, and optional guidance or default values. + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited =true)] + public class ParameterDateConfigAttribute : ExternalConfigAttribute + { + /// + /// Initializes a new instance of the class. + /// + /// This constructor sets the external configuration type to . It is used to define the type of external configuration that this + /// attribute represents. + public ParameterDateConfigAttribute():base(ExternalConfigType.ParameterDate) + { + // Intentionally left blank, this is used to define the type of external configuration this attribute represents. + } + + + /// + /// The name of the command, project, or project folder that this parameter date is associated with. + /// + public string Parent { get; init; } + + /// + /// Flag that determines if the parameter date is required in order for the automation to run. + /// + public bool IsRequired { get; init; } = false; + + /// + /// Gets or sets the guidance text that provides instructions for using the parameter date configuration. + /// + public string Guidance { get; init; } + + /// + /// Gets or sets the URL that provides additional guidance or documentation. + /// + public string GuidanceUrl { get; init; } + + /// + /// The default value for the parameter date configuration. This can be used to provide a pre-defined value that will be used if no other value is specified. + /// + public string DefaultValue { get; init; } = null; + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterDateExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterDateExternalConfigMap.cs new file mode 100644 index 0000000..aa10d62 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterDateExternalConfigMap.cs @@ -0,0 +1,50 @@ +using CodeFactory.WinVs.Commands; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Represents a configuration mapping for a parameter of type . + /// + /// This class is used to define and manage configuration settings for date parameters, including + /// their default values, associated parent context, and guidance information. It extends the base class with additional properties specific to date parameters. + public class ParameterDateExternalConfigMap:ExternalConfigMap + { + /// + /// Initializes a new instance of the class with the specified + /// configuration details. + /// + /// The name of the configuration parameter. + /// A value indicating whether the configuration parameter is required. if required; + /// otherwise, . + /// The name of the parent configuration group or section. + /// The default value for the configuration parameter, or if no default value is + /// specified. + /// Guidance or description for the configuration parameter. + /// A URL providing additional guidance or documentation for the configuration parameter. + /// An action delegate used to set the configuration value. The first parameter represents the target object, + /// and the second parameter represents the value to set. + public ParameterDateExternalConfigMap(string name, bool isRequired, string parent, DateTime? defaultValue, string guidance, string guidanceUrl, IPropertySetter setConfigurationValue) : base(ExternalConfigType.ParameterDate, name, isRequired, guidance, guidanceUrl, setConfigurationValue) + { + Parent = parent; + DefaultValue = defaultValue; + } + + + /// + /// The name of the commmand, project, or project folder that this parameter string is associated with. + /// + public string Parent { get; init; } + + /// + /// The default value for the parameter date configuration. This can be used to provide a pre-defined value that will be used if no other value is specified. + /// + public DateTime? DefaultValue { get; init; } = null; + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterListConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterListConfigAttribute.cs new file mode 100644 index 0000000..7fb9e96 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterListConfigAttribute.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies metadata for a parameter list associated with a command, project, or project folder. + /// + /// This attribute is used to annotate properties that represent parameter lists in automation + /// scenarios. It provides metadata such as the parent entity the parameter list is associated with, whether the + /// parameter list is required, and optional guidance or documentation links for configuration. + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class ParameterListConfigAttribute : ExternalConfigAttribute + { + + /// + /// Initializes a new instance of the class. + /// + /// This attribute is used to specify that the associated member represents a parameter + /// list configuration. It is initialized with the value to + /// define the type of external configuration. + public ParameterListConfigAttribute():base(ExternalConfigType.ParameterList) + { + // Intentionally left blank, this is used to define the type of external configuration this attribute represents. + } + + + /// + /// The name of the command, project, or project folder that this parameter list is associated with. + /// + public string Parent { get; set; } + + /// + /// Flag that determines if the parameter list is required in order for the automation to run. + /// + public bool IsRequired { get; set; } = false; + + /// + /// Gets or sets the guidance text that provides instructions for using the parameter list configuration. + /// + public string Guidance { get; set; } + + /// + /// Gets or sets the URL that provides additional guidance or documentation. + /// + public string GuidanceUrl { get; set; } + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterListExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterListExternalConfigMap.cs new file mode 100644 index 0000000..a147e41 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterListExternalConfigMap.cs @@ -0,0 +1,49 @@ +using CodeFactory.WinVs.Commands; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Represents a configuration mapping for a parameter list, including associated metadata and behavior. + /// + /// This class is used to define a configuration parameter that accepts a list of string values. + /// It includes metadata such as whether the parameter is required, a default value, and optional guidance or + /// documentation links. + public class ParameterListExternalConfigMap:ExternalConfigMap + { + /// + /// Initializes a new instance of the class, representing a + /// configuration mapping for a parameter list with associated metadata and behavior. + /// + /// The name of the configuration parameter. Cannot be null or empty. + /// A value indicating whether the parameter is required. if the parameter is required; + /// otherwise, . + /// The name of the parent configuration group or section. Can be null or empty if no parent exists. + /// The default value for the parameter list. If null, an empty list will be used as the default. + /// Guidance or description for the parameter's purpose or usage. Can be null or empty if no guidance is + /// provided. + /// A URL pointing to additional guidance or documentation for the parameter. Can be null or empty if no URL is + /// provided. + /// An action delegate used to set the configuration value. The first parameter represents the target object, + /// and the second parameter represents the value to set. Cannot be null. + public ParameterListExternalConfigMap( string name, bool isRequired, string parent, List defaultValue, string guidance, string guidanceUrl, IPropertySetter setConfigurationValue) : base(ExternalConfigType.ParameterList, name, isRequired, guidance, guidanceUrl, setConfigurationValue) + { + Parent = parent; + DefaultValue = defaultValue ?? new List(); + } + + /// + /// The name of the commmand, project, or project folder that this parameter string is associated with. + /// + public string Parent { get; init; } + + /// + /// The default value for the parameter list configuration. This can be used to provide a pre-defined value that will be used if no other value is specified. + /// + public List DefaultValue { get; init; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterSelectedValueConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterSelectedValueConfigAttribute.cs new file mode 100644 index 0000000..0b15074 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterSelectedValueConfigAttribute.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies metadata for a parameter's selected value, including its parent context, guidance, and default value. + /// + /// This attribute is used to annotate properties that represent a parameter's selected value in + /// an automation context. It provides additional metadata such as whether the value is required, guidance for + /// usage, and a default value. + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class ParameterSelectedValueConfigAttribute: ExternalConfigAttribute + { + /// + /// Initializes a new instance of the class. + /// + /// This constructor sets the external configuration type to . It is used to define the type of external configuration + /// that this attribute represents. + + public ParameterSelectedValueConfigAttribute():base(ExternalConfigType.ParameterSelectedValue) + { + // Intentionally left blank, this is used to define the type of external configuration this attribute represents. + } + + /// + /// The name of the command, project, or project folder that this parameter selected value is associated with. + /// + public string Parent { get; set; } + + /// + /// Flag that determines if the parameter selected value is required in order for the automation to run. + /// + public bool IsRequired { get; set; } = false; + + /// + /// Gets or sets the guidance text that provides instructions for using the parameter selected value configuration. + /// + public string Guidance { get; set; } + + /// + /// Gets or sets the URL that provides additional guidance or documentation. + /// + public string GuidanceUrl { get; set; } + + /// + /// The default value for the parameter selected value configuration. This can be used to provide a pre-defined value that will be used if no other value is specified. + /// + public string DefaultValue { get; set; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterSelectedValueExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterSelectedValueExternalConfigMap.cs new file mode 100644 index 0000000..bf920bb --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterSelectedValueExternalConfigMap.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Represents a configuration map for a parameter with a predefined set of selectable values. + /// + /// This class is used to define a parameter configuration where the user can select a value from + /// a predefined list of options. It includes metadata such as the parameter's name, whether it is required, its + /// default value, and additional guidance or documentation. + public class ParameterSelectedValueExternalConfigMap : ExternalConfigMap + { + + /// + /// Initializes a new instance of the class with the specified configuration details. + /// + /// The name of the parameter. + /// A value indicating whether the parameter is required. + /// The name of the parent configuration group or section. + /// The default value for the parameter. + /// List of the values that can be selected from. + /// Guidance or description for the parameter. + /// A URL providing additional guidance or documentation for the parameter. + /// An action delegate used to set the configuration value. + public ParameterSelectedValueExternalConfigMap(string name, bool isRequired, string parent, string defaultValue, List selectionValues, string guidance, string guidanceUrl, IPropertySetter setConfigurationValue) + : base(ExternalConfigType.ParameterSelectedValue, name, isRequired, guidance, guidanceUrl, setConfigurationValue) + { + Parent = parent; + DefaultValue = defaultValue; + SelectionValues = selectionValues ?? new List(); + + } + + /// + /// The name of the command, project, or project folder that this parameter is associated with. + /// + public string Parent { get; init; } + + /// + /// The default value for the selected value parameter configuration. + /// + public string DefaultValue { get; init; } + + /// + /// Gets the collection of selection values. + /// + public List SelectionValues { get; init; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterStringConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterStringConfigAttribute.cs new file mode 100644 index 0000000..b613fa7 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterStringConfigAttribute.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies configuration metadata for a parameter string used in external automation settings. + /// + /// This attribute is applied to properties to define their association with a parameter string + /// configuration. It provides metadata such as whether the parameter is required, guidance text, and a default + /// value. The external configuration type is set to . + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class ParameterStringConfigAttribute: ExternalConfigAttribute + { + /// + /// Initializes a new instance of the class. + /// + /// This constructor sets the external configuration type to . It is used to define the type of external configuration that this attribute represents. + public ParameterStringConfigAttribute() : base(ExternalConfigType.ParameterString) + { + // Intentionally left blank, this is used to define the type of external configuration this attribute represents. + } + + /// + /// The name of the commmand, project, or project folder that this parameter string is associated with. + /// + public string Parent { get; set; } + + /// + /// Flag that determines if the parameter string is required in order for the automation to run. + /// + public bool IsRequired { get; set; } = false; + + /// + /// Gets or sets the guidance text that provides instructions for using the parameter string configuration. + /// + public string Guidance { get; set; } + + /// + /// Gets or sets the URL that provides additional guidance or documentation. + /// + public string GuidanceUrl { get; set; } + + /// + /// The default value for the parameter string configuration. This can be used to provide a pre-defined value that will be used if no other value is specified. + /// + public string DefaultValue { get; set; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterStringExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterStringExternalConfigMap.cs new file mode 100644 index 0000000..45d8f30 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ParameterStringExternalConfigMap.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Represents an external configuration map for a parameter string, providing metadata such as the associated + /// parent, default value, and guidance information. + /// + /// This class is used to define a parameter string configuration that can be associated with a + /// specific command, project, or project folder. It includes metadata such as the parent name, a default value, + /// and optional guidance text or URL for additional context. + public class ParameterStringExternalConfigMap:ExternalConfigMap + { + /// + /// Initializes a new instance of the class with the specified name, guidance, and guidance URL. + /// + /// The name of the external configuration map. + /// Flag that determines if the parameter string is required for execution of the command. + /// The name of the command, project, or project file that hosts this parameter. + /// The default value to set in the configuration. + /// The guidance text associated with the configuration map. + /// The URL providing additional guidance for the configuration map. + /// /// An action delegate used to set the configuration value. The first parameter represents the target object, + /// and the second parameter represents the value to set. + public ParameterStringExternalConfigMap(string name, bool isRequired, string parent, string defaultValue, string guidance, string guidanceUrl,IPropertySetter setConfigurationValue) : base(ExternalConfigType.ParameterString, name, isRequired, guidance, guidanceUrl, setConfigurationValue) + { + Parent = parent; + DefaultValue = defaultValue; + + } + + /// + /// The name of the commmand, project, or project folder that this parameter string is associated with. + /// + public string Parent { get; init; } + + /// + /// The default value for the parameter string configuration. This can be used to provide a pre-defined value that will be used if no other value is specified. + /// + public string DefaultValue { get; init; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectConfigAttribute.cs new file mode 100644 index 0000000..596f2e9 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectConfigAttribute.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies that a property is associated with project-level external configuration. + /// + /// This attribute is used to indicate that a property represents a configuration setting + /// specific to a project. It inherits from and is preconfigured to represent + /// the configuration type. + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class ProjectConfigAttribute: ExternalConfigAttribute + { + /// + /// Initializes a new instance of the class, representing an external + /// configuration of type . + /// + /// This attribute is used to specify that a class or member is associated with + /// project-level external configuration. It inherits from a base attribute that defines the type of external + /// configuration. + public ProjectConfigAttribute() : base(ExternalConfigType.Project) + { + // Intentionally left blank, this is used to define the type of external configuration this attribute represents. + } + + /// + /// Flag that determines if the project configuration is required in order for the automation to run. + /// + public bool IsRequired { get; set; } + + /// + /// Gets the guidance text associated with the project configuration. This can provide additional context or instructions for users. + /// + public string Guidance { get; set; } + + /// + /// Gets or sets the URL that provides additional guidance or documentation. + /// + public string GuidanceUrl { get; set; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectExternalConfigMap.cs new file mode 100644 index 0000000..dd16521 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectExternalConfigMap.cs @@ -0,0 +1,35 @@ +using CodeFactory.WinVs.Commands; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Represents an external configuration map specific to a project, providing metadata and functionality for setting + /// configuration values. + /// + /// This class is used to define a project-specific external configuration map, including its + /// name, whether it is required, associated guidance, and a delegate for setting configuration values. It extends + /// the class with a predefined configuration type of . + public class ProjectExternalConfigMap : ExternalConfigMap + { + /// + /// Initializes a new instance of the class with the specified name, guidance, and guidance URL. + /// + /// The name of the external configuration map. + /// Flag that determines if the project is required for execution of the command. + /// The guidance text associated with the configuration map. + /// The URL providing additional guidance for the configuration map. + /// An action delegate used to set the configuration value. The first parameter represents the target object, + /// and the second parameter represents the value to set. + public ProjectExternalConfigMap(string name, bool isRequired, string guidance, string guidanceUrl, IPropertySetter setConfigurationValue) + : base(ExternalConfigType.Project, name, isRequired, guidance, guidanceUrl, setConfigurationValue) + { + //Intentionally left blank + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectFolderConfigAttribute.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectFolderConfigAttribute.cs new file mode 100644 index 0000000..4a49297 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectFolderConfigAttribute.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Specifies that the associated external configuration is of type . + /// + /// This attribute is used to indicate that a property represents a project folder-based + /// configuration. It is primarily intended for scenarios where configuration data is organized within a project + /// folder structure. + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class ProjectFolderConfigAttribute:ExternalConfigAttribute + { + /// + /// Initializes a new instance of the class. + /// + /// This attribute is used to specify that the associated external configuration is of + /// type . It is primarily intended for use in scenarios where + /// project folder-based configuration is required. + public ProjectFolderConfigAttribute():base(ExternalConfigType.Folder) + { + // Intentionally left blank, this is used to define the type of external configuration this attribute represents. + } + + + /// + /// The parent project that hosts this project folder configuration. + /// + public string Parent { get; set; } + + /// + /// Flag that determines if the project folder configuration is required in order for the automation to run. + /// + public bool IsRequired { get; set; } = false; + + /// + /// Gets the path where the project folder is located. This should be a relative path from the parent project root. + /// + /// + /// If the path is more then one level deep, then use the forward slash (/) as the directory separator. + /// Example FirstFolder/SecondFolder/ThirdFolder + /// + public string Path { get; set; } + + /// + /// Guidance or description for the project folder configuration, providing additional context or instructions. + /// + public string Guidance { get; set; } + + /// + /// Gets or sets the URL that provides additional guidance or documentation. + /// + public string GuidanceUrl { get; set; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectFolderExternalConfigMap.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectFolderExternalConfigMap.cs new file mode 100644 index 0000000..2ba1e90 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/ProjectFolderExternalConfigMap.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + public class ProjectFolderExternalConfigMap : ExternalConfigMap + { + /// + /// Initializes a new instance of the class, representing an + /// external configuration mapping for a project folder. + /// + /// The name of the configuration mapping. + /// A value indicating whether the configuration mapping is required. if required; + /// otherwise, . + /// The parent folder associated with the configuration mapping. + /// The file system path of the folder being mapped. + /// Guidance or description for the configuration mapping. + /// A URL providing additional guidance or documentation for the configuration mapping. + /// An action delegate used to set the configuration value. The first parameter represents the target object, + /// and the second parameter represents the value to be set. + public ProjectFolderExternalConfigMap(string name, bool isRequired,string parent, string path, string guidance, string guidanceUrl, IPropertySetter setConfigurationValue) : base(ExternalConfigType.Folder, name, isRequired, guidance, guidanceUrl, setConfigurationValue) + { + Path = path; + Parent = parent; + } + + /// + /// Relative path to the project folder from the project root. + /// + public string Path { get; init; } + + /// + /// Get the project that this project folder is associated with. + /// + public string Parent { get; init; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/PropertySetter.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/PropertySetter.cs new file mode 100644 index 0000000..62d9cf3 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/PropertySetter.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Provides a mechanism to set the value of a property on a target object of a specified type. + /// + /// This class is designed to encapsulate the logic for setting a property value using a + /// delegate. It supports dynamic property setting through reflection and delegate creation. + /// The type of the target object on which the property is set. Must be a reference type. + /// The type of the property value to be set. + public class PropertySetter : IPropertySetter where C : class + { + // Holds the delegate that sets the property value on the target class. + private readonly Action _setPropertyValue; + + /// + /// Initializes a new instance of the class with the specified property + /// setter action. + /// + /// An action that sets the value of a property. The action takes two parameters: the instance of type + /// and the value of type to set. + /// Thrown if is . + private PropertySetter(Action setPropertyValue) + { + _setPropertyValue = setPropertyValue ?? throw new ArgumentNullException(nameof(setPropertyValue)); + } + + + /// + /// Sets the value of a specified property on the target object. + /// + /// This method uses a delegate to set the property value on the specified object. Ensure + /// that the types of the parameters match the expected types to avoid runtime exceptions. + /// The object whose property value is to be set. Must be an instance of the target class type. + /// The value to assign to the property. Must be compatible with the property's type. + public void SetPropertyValue(object targetClass, object propertyValue) + { + _setPropertyValue.Invoke((C)targetClass, (T)propertyValue); + } + + + /// + /// Initializes a new instance of an for the specified property setter method. + /// + /// The representing the property setter method to be used. + /// An instance that can set the property value using the specified method. + public static IPropertySetter Init(MethodInfo propertySetMethod) + { + var action = (Action)Delegate.CreateDelegate(typeof(Action), propertySetMethod); + + return new PropertySetter(action); + } + + + } + +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/StandardCommandCategories.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/StandardCommandCategories.cs new file mode 100644 index 0000000..9339f71 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Commands/StandardCommandCategories.cs @@ -0,0 +1,46 @@ +using CodeFactory.WinVs.Commands.SolutionExplorer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Commands +{ + /// + /// Provides a set of predefined command category names used to group commands in a development environment. + /// + /// These categories are commonly used to organize commands related to solutions, projects, + /// documents, and specific file types, such as C# source files, within an integrated development environment + /// (IDE). + public static class StandardCommandCategories + { + /// + /// Solution category, typically used for commands that operate at the solution level. + /// + public const string Solution = "Solution"; + + /// + /// Project category, typically used for commands that operate at the project level. + /// + public const string Project = "Project"; + + /// + /// Project Folder category, typically used for commands that operate on project folders. + /// + public const string ProjectFolder = "Project Folder"; + + /// + /// Document category, typically used for commands that operate on documents or files within a project. + /// + public const string Document = "Document"; + + /// + /// CSharp Source category, typically used for commands that operate on C# source files. + /// + /// This constant can be used to identify or tag C# source code in scenarios where + /// multiple source types are being handled or processed. + public const string CSharpSource = "CSharpSource"; + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsClassExtensions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsClassExtensions.cs new file mode 100644 index 0000000..9a301af --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsClassExtensions.cs @@ -0,0 +1,46 @@ +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Static class that provides extension methods for the class. + /// + public static class CsClassExtensions + { + + /// + /// Extension method that generates the fully qualified type name of the specified class, including its namespace and generic + /// parameters if applicable. + /// + /// This method constructs the type name by combining the namespace, class name, and + /// generic parameter signature (if the class is generic). If a is provided, it is + /// used to resolve namespaces; otherwise, a default is used. + /// The instance representing the class for which the type name is generated. Must not be + /// null and must be loaded. + /// An optional instance used to resolve and append namespaces. If null, + /// a new instance will be created. + /// An optional list of objects used to map namespaces during the generation of + /// generic parameter signatures. + /// A representing the fully qualified type name of the class, including its namespace and + /// generic parameters if applicable. Returns null if the is null or + /// not loaded. + public static string GenerateClassTypeName(this CsClass source, NamespaceManager manager = null, + List mappedNamespaces = null) + { + if (source == null || !source.IsLoaded) return null; + + StringBuilder stringBuilder = new StringBuilder(); + NamespaceManager nsManager = manager ?? new NamespaceManager(); + string str = nsManager.AppendingNamespace(source.Namespace); + stringBuilder.Append(str == null ? source.Name : str + "." + source.Name); + if (source.IsGeneric) + stringBuilder.Append(source.GenericParameters.GenerateCSharpGenericParametersSignature(manager, mappedNamespaces)); + return stringBuilder.ToString(); + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsClassResult.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsClassResult.cs new file mode 100644 index 0000000..99a5453 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsClassResult.cs @@ -0,0 +1,87 @@ +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Represents the result of processing a C# class, including its name, status, source, and the resulting class + /// object. + /// + /// This class is used to encapsulate the outcome of processing a C# class, such as whether it + /// was created, updated, or skipped. It provides methods to update the result with new information and to validate + /// the integrity of the result. + public class CsClassResult : CsSourceResult + { + /// + /// The name of the class that was processed. + /// + public required string ClassName { get; init; } + + /// + /// The class that was created or updated. + /// + public required CsClass Class { get; init; } + + /// + /// Updates the current class result with an updated class result. Use this to merge a 'created' result with an 'updated' result so it returns 'created' but with the most recent source code + /// + /// The updated class result + /// + public CsClassResult UpdateWith(CsClassResult updatedResult) + { + if (updatedResult == null) + return this; + + ResultStatusType status; + + if (Status == ResultStatusType.Created) + { + status = ResultStatusType.Created; + } + else if (updatedResult.Status == ResultStatusType.Skipped) + { + status = updatedResult.Status; + } + else + { + status = updatedResult.Status; + } + + return new CsClassResult + { + ClassName = updatedResult.ClassName, + Status = status, + Source = updatedResult.Source, + Class = updatedResult.Class + }; + } + + /// + /// Validates the result of the class result. This checks to ensure that the source and class are not null and throws an exception if they are. + /// + /// The method name that called the validation. + /// + /// Raised if the source or the class models are null. + public override void ValidateResult([CallerMemberName] string callerName = null) + { + string classDescriptor = string.Empty; + if (Status == ResultStatusType.Created) + classDescriptor = "newly created "; + else if (Status == ResultStatusType.Updated) + classDescriptor = "updated "; + else if (Status == ResultStatusType.Skipped) + classDescriptor = ""; + + if (Source == null) + throw new CodeFactoryException($"Failed to load source for {classDescriptor}'{ClassName}', cannot complete {callerName}."); + if (Class == null) + throw new CodeFactoryException($"Failed to load class for {classDescriptor}'{ClassName}', cannot complete {callerName}."); + + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsContainerResult.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsContainerResult.cs new file mode 100644 index 0000000..2502c6f --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsContainerResult.cs @@ -0,0 +1,87 @@ +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Represents the result of processing a C# container, including its name, status, source, and the resulting container + /// object. + /// + /// This class is used to encapsulate the outcome of processing a C# container, such as whether it + /// was created, updated, or skipped. It provides methods to update the result with new information and to validate + /// the integrity of the result. + public class CsContainerResult : CsSourceResult + { + /// + /// The name of the container that was processed. + /// + public required string ContainerName { get; init; } + + /// + /// The container that was created or updated. + /// + public required CsContainer Container { get; init; } + + /// + /// Updates the current container result with an updated container result. Use this to merge a 'created' result with an 'updated' result so it returns 'created' but with the most recent source code + /// + /// The updated container result + /// + public CsContainerResult UpdateWith(CsContainerResult updatedResult) + { + if (updatedResult == null) + return this; + + ResultStatusType status; + + if (Status == ResultStatusType.Created) + { + status = ResultStatusType.Created; + } + else if (updatedResult.Status == ResultStatusType.Skipped) + { + status = updatedResult.Status; + } + else + { + status = updatedResult.Status; + } + + return new CsContainerResult + { + ContainerName = updatedResult.ContainerName, + Status = status, + Source = updatedResult.Source, + Container = updatedResult.Container + }; + } + + /// + /// Validates the result of the container result. This checks to ensure that the source and container are not null and throws an exception if they are. + /// + /// The method name that called the validation. + /// + /// Raised if the source or the container models are null. + public override void ValidateResult([CallerMemberName] string callerName = null) + { + string containerDescriptor = string.Empty; + if (Status == ResultStatusType.Created) + containerDescriptor = "newly created "; + else if (Status == ResultStatusType.Updated) + containerDescriptor = "updated "; + else if (Status == ResultStatusType.Skipped) + containerDescriptor = ""; + + if (Source == null) + throw new CodeFactoryException($"Failed to load source for {containerDescriptor}'{ContainerName}', cannot complete {callerName}."); + if (Container == null) + throw new CodeFactoryException($"Failed to load container for {containerDescriptor}'{ContainerName}', cannot complete {callerName}."); + + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsFactoryManagement.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsFactoryManagement.cs new file mode 100644 index 0000000..83c5a58 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsFactoryManagement.cs @@ -0,0 +1,807 @@ +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Provides functionality for managing C# code elements, namespaces, and using statements within a Visual Studio + /// context. + /// + /// This class facilitates the management of namespaces and using statements for C# code + /// elements, including types, attributes, fields, properties, methods, events, and other supported model types. It + /// also provides methods to update the namespace manager and mapped namespaces, ensuring that all required using + /// statements are added for proper compilation. + public class CsFactoryManagement: ICsFactoryManagement + { + //Backing fields for the properties defined in the interface. + private readonly IVsActions _vsActions; + private NamespaceManager _namespaceManager; + private ImmutableArray _mappedNamespaces; + + /// + /// Initializes a new instance of the class, which manages the creation and + /// organization of C# code elements within a Visual Studio environment. + /// + /// The interface providing actions and utilities for interacting with Visual Studio. This parameter cannot be + /// . + /// An optional instance for managing namespaces. If not provided, a default + /// instance will be created. + /// An optional collection of objects to define namespace mappings. If not provided, + /// an empty collection will be used. + /// Thrown if is . + public CsFactoryManagement( IVsActions vsActions, NamespaceManager namespaceManager = null, IEnumerable mapNamespaces = null) + { + _vsActions = vsActions ?? throw new ArgumentNullException(nameof(vsActions), "The Visual Studio actions interface cannot be null."); + + _namespaceManager = namespaceManager ?? new NamespaceManager(); + + _mappedNamespaces = mapNamespaces?.ToImmutableArray() ?? ImmutableArray.Empty; + } + + /// + /// The CodeFactory Visual Studio actions that can be performed. + /// + public IVsActions VsActions => _vsActions; + + /// + /// Gets the instance used to determine the qualified namespaces for C# code elements. + /// + public NamespaceManager NamespaceManager => _namespaceManager; + + /// + /// Gets the collection of mapped namespaces. + /// + public IReadOnlyList MappedNamespaces => _mappedNamespaces; + + /// + /// Updates the collection of mapped namespaces with the specified values. + /// + /// This method replaces the current collection of mapped namespaces with the provided + /// collection. If the input is , the collection is set to an empty, immutable + /// list. + /// A collection of objects representing the namespaces to be mapped. If is , the collection will be cleared. + public void UpdateMappedNamespaces(IEnumerable mappedNamespaces) + { + if (mappedNamespaces == null) return; + + _mappedNamespaces = mappedNamespaces?.ToImmutableArray() ?? ImmutableArray.Empty; + } + + /// + /// Updates the namespace manager by adding any missing using statements for the specified model. + /// + /// This method determines the type of the provided and + /// processes it accordingly to ensure that all required using statements are added to the namespace manager. + /// If the model type is unsupported, the method performs no action. + /// The model to process. The model must not be and should represent a valid code + /// element, such as a type, attribute, field, property, method, event, or other supported model type. + /// + public async Task UpdateNamespaceManager(CsModel csModel) + { + + if(csModel == null) return; + + switch (csModel.ModelType) + { + + case CsModelType.Type: + + var sourceType = csModel as CsType; + + await AddMissingUsingStatementsAsync(sourceType); + + break; + + case CsModelType.Attribute: + + var sourceAttribute = csModel as CsAttribute; + + await AddMissingUsingStatementsAsync(sourceAttribute); + + break; + + case CsModelType.Field: + + var sourceField = csModel as CsField; + + await AddMissingUsingStatementsAsync(sourceField); + + break; + + case CsModelType.Property: + + var sourceProperty = csModel as CsProperty; + + await AddMissingUsingStatementsAsync(sourceProperty); + + break; + + case CsModelType.Method: + + var sourceMethod = csModel as CsMethod; + + await AddMissingUsingStatementsAsync(sourceMethod); + + break; + + + case CsModelType.Event: + + var sourceEvent = csModel as CsEvent; + + await AddMissingUsingStatementsAsync(sourceEvent); + + break; + + + case CsModelType.Record: + + var sourceRecord = csModel as CsRecord; + + await AddMissingUsingStatementsAsync(sourceRecord); + + break; + + + case CsModelType.RecordStructure: + + var sourceRecordStructure = csModel as CsRecordStructure; + + await AddMissingUsingStatementsAsync(sourceRecordStructure); + + + break; + + + case CsModelType.Interface: + + var sourceInterface = csModel as CsInterface; + + await AddMissingUsingStatementsAsync(sourceInterface); + + break; + + + case CsModelType.Class: + + var sourceClass = csModel as CsClass; + + await AddMissingUsingStatementsAsync(sourceClass); + + break; + + case CsModelType.Structure: + + var sourceStructure = csModel as CsStructure; + + await AddMissingUsingStatementsAsync(sourceStructure); + + break; + + case CsModelType.Source: + + var sourceSource = csModel as CsSource; + + await AddMissingUsingStatementsAsync(sourceSource); + + break; + + default: + + // Intentionally left blank, as this is a catch-all for unsupported types. + + break; + } + } + + + /// + /// Adds missing using statements to the specified source code element and its nested elements. + /// + /// This method recursively processes the provided source code element, including its + /// namespaces, interfaces, classes, structures, records, and record structures, to ensure that all required + /// using statements are added. If a namespace reference or alias is detected, it is added as a using + /// statement. Nested elements are processed recursively to ensure completeness. + /// The object representing the source code element to process. This parameter cannot be + /// . + /// A that represents the asynchronous operation. + private async Task AddMissingUsingStatementsAsync(CsSource source) + { + if (source == null) return; + + if (source.NamespaceReferences.Any()) + { + foreach (var namespaceReference in source.NamespaceReferences) + { + if (namespaceReference == null) continue; + + await UsingStatementAddAsync(namespaceReference.ReferenceNamespace, namespaceReference.Alias); + } + } + + if (source.Interfaces.Any()) + { + foreach (var sourceInterface in source.Interfaces) + { + await AddMissingUsingStatementsAsync(sourceInterface); + } + } + + if (source.Classes.Any()) + { + foreach (var sourceClass in source.Classes) + { + await AddMissingUsingStatementsAsync(sourceClass); + } + } + + if (source.Structures.Any()) + { + foreach (var sourceStructure in source.Structures) + { + await AddMissingUsingStatementsAsync(sourceStructure); + } + } + + if (source.Records.Any()) + { + foreach (var sourceRecord in source.Records) + { + await AddMissingUsingStatementsAsync(sourceRecord); + } + } + + if (source.RecordStructures.Any()) + { + foreach (var sourceRecordStructure in source.RecordStructures) + { + await AddMissingUsingStatementsAsync(sourceRecordStructure); + } + } + } + + /// + /// Recursively adds missing using statements for the specified interface and its related members. + /// + /// This method processes the specified interface and its associated generic types, + /// attributes, properties, methods, and events to ensure that all necessary using statements are added. The + /// operation is performed recursively for any nested or related members. + /// The interface for which to add missing using statements. Cannot be . + /// + private async Task AddMissingUsingStatementsAsync(CsInterface csInterface) + { + if (csInterface == null) return; + if (csInterface.HasStrongTypesInGenerics) + { + foreach (var sourceGenericType in csInterface.GenericTypes) + { + await AddMissingUsingStatementsAsync(sourceGenericType); + } + } + if (csInterface.HasAttributes) + { + foreach (var interfaceAttribute in csInterface.Attributes) + { + await AddMissingUsingStatementsAsync(interfaceAttribute); + } + } + if (csInterface.Properties.Any()) + { + foreach (var interfaceProperty in csInterface.Properties) + { + await AddMissingUsingStatementsAsync(interfaceProperty); + } + } + if (csInterface.Methods.Any()) + { + foreach (var interfaceMethod in csInterface.Methods) + { + await AddMissingUsingStatementsAsync(interfaceMethod); + } + } + if(csInterface.Events.Any()) + { + foreach (var interfaceEvent in csInterface.Events) + { + await AddMissingUsingStatementsAsync(interfaceEvent); + } + } + + if(csInterface.NestedClasses.Any()) + { + foreach (var nestedClass in csInterface.NestedClasses) + { + await AddMissingUsingStatementsAsync(nestedClass); + } + } + + if(csInterface.NestedStructures.Any()) + { + foreach (var nestedStructure in csInterface.NestedStructures) + { + await AddMissingUsingStatementsAsync(nestedStructure); + } + } + + if(csInterface.NestedInterfaces.Any()) + { + foreach (var nestedInterface in csInterface.NestedInterfaces) + { + await AddMissingUsingStatementsAsync(nestedInterface); + } + } + } + + /// + /// Recursively adds missing using statements to the specified C# structure and its nested elements. + /// + /// This method processes the provided and its nested + /// elements, including generic types, attributes, properties, methods, fields, and events, to ensure that all + /// required using statements are added. It performs the operation recursively for any nested + /// structures. + /// The C# structure to analyze and update. Cannot be . + /// A that represents the asynchronous operation. + private async Task AddMissingUsingStatementsAsync(CsStructure csStructure) + { + if (csStructure == null) return; + if (csStructure.HasStrongTypesInGenerics) + { + foreach (var sourceGenericType in csStructure.GenericTypes) + { + await AddMissingUsingStatementsAsync(sourceGenericType); + } + } + if (csStructure.HasAttributes) + { + foreach (var structureAttribute in csStructure.Attributes) + { + await AddMissingUsingStatementsAsync(structureAttribute); + } + } + if (csStructure.Properties.Any()) + { + foreach (var structureProperty in csStructure.Properties) + { + await AddMissingUsingStatementsAsync(structureProperty); + } + } + if (csStructure.Methods.Any()) + { + foreach (var structureMethod in csStructure.Methods) + { + await AddMissingUsingStatementsAsync(structureMethod); + } + } + if (csStructure.Fields.Any()) + { + foreach (var structureField in csStructure.Fields) + { + await AddMissingUsingStatementsAsync(structureField); + } + } + if(csStructure.Events.Any()) + { + foreach (var structureEvent in csStructure.Events) + { + await AddMissingUsingStatementsAsync(structureEvent); + } + } + + if(csStructure.NestedClasses.Any()) + { + foreach (var nestedClass in csStructure.NestedClasses) + { + await AddMissingUsingStatementsAsync(nestedClass); + } + } + + if(csStructure.NestedStructures.Any()) + { + foreach (var nestedStructure in csStructure.NestedStructures) + { + await AddMissingUsingStatementsAsync(nestedStructure); + } + } + + if(csStructure.NestedInterfaces.Any()) + { + foreach (var nestedInterface in csStructure.NestedInterfaces) + { + await AddMissingUsingStatementsAsync(nestedInterface); + } + } + } + + /// + /// Recursively adds missing using statements for the specified C# record structure and its members. + /// + /// This method processes the provided and its + /// nested members (such as generic types, attributes, properties, methods, fields, and events) to ensure that + /// all required using statements are added. If the structure or any of its members reference types that + /// require additional using statements, those statements will be added recursively. + /// The C# record structure for which missing using statements should be added. This includes its generic + /// types, attributes, properties, methods, fields, and events. + + private async Task AddMissingUsingStatementsAsync(CsRecordStructure csRecordStructure) + { + if (csRecordStructure == null) return; + if (csRecordStructure.HasStrongTypesInGenerics) + { + foreach (var sourceGenericType in csRecordStructure.GenericTypes) + { + await AddMissingUsingStatementsAsync(sourceGenericType); + } + } + if (csRecordStructure.HasAttributes) + { + foreach (var recordAttribute in csRecordStructure.Attributes) + { + await AddMissingUsingStatementsAsync(recordAttribute); + } + } + if (csRecordStructure.Properties.Any()) + { + foreach (var recordProperty in csRecordStructure.Properties) + { + await AddMissingUsingStatementsAsync(recordProperty); + } + } + if (csRecordStructure.Methods.Any()) + { + foreach (var recordMethod in csRecordStructure.Methods) + { + await AddMissingUsingStatementsAsync(recordMethod); + } + } + if (csRecordStructure.Fields.Any()) + { + foreach (var recordField in csRecordStructure.Fields) + { + await AddMissingUsingStatementsAsync(recordField); + } + } + if(csRecordStructure.Events.Any()) + { + foreach (var recordEvent in csRecordStructure.Events) + { + await AddMissingUsingStatementsAsync(recordEvent); + } + } + + } + + /// + /// Recursively adds missing using statements for the specified source record and its members. + /// + /// This method traverses the structure of the provided + /// and ensures that all necessary using statements are added for its components. It processes generic types, + /// attributes, and members such as properties, methods, fields, and events recursively. + /// The source record for which missing using statements should be added. This includes processing its generic + /// types, attributes, properties, methods, fields, and events. + private async Task AddMissingUsingStatementsAsync(CsRecord sourceRecord) + { + if (sourceRecord == null) return; + if (sourceRecord.HasStrongTypesInGenerics) + { + foreach (var sourceGenericType in sourceRecord.GenericTypes) + { + await AddMissingUsingStatementsAsync(sourceGenericType); + } + } + if (sourceRecord.HasAttributes) + { + foreach (var recordAttribute in sourceRecord.Attributes) + { + await AddMissingUsingStatementsAsync(recordAttribute); + } + } + if (sourceRecord.Properties.Any()) + { + foreach (var recordProperty in sourceRecord.Properties) + { + await AddMissingUsingStatementsAsync(recordProperty); + } + } + if (sourceRecord.Methods.Any()) + { + foreach (var recordMethod in sourceRecord.Methods) + { + await AddMissingUsingStatementsAsync(recordMethod); + } + } + if (sourceRecord.Fields.Any()) + { + foreach (var recordField in sourceRecord.Fields) + { + await AddMissingUsingStatementsAsync(recordField); + } + } + if(sourceRecord.Events.Any()) + { + foreach (var recordEvent in sourceRecord.Events) + { + await AddMissingUsingStatementsAsync(recordEvent); + } + } + } + + + + /// + /// Recursively adds missing using statements for the specified class and its members. + /// + /// This method traverses the structure of the provided class, including its members and + /// related types, to ensure that all necessary using statements are added. If + /// is null, the method returns without performing any operations. + /// The instance for which missing using statements should be added. This includes + /// processing the class's generic types, attributes, properties, methods, fields, and events. + private async Task AddMissingUsingStatementsAsync(CsClass sourceClass) + { + if (sourceClass == null) return; + + if (sourceClass.HasStrongTypesInGenerics) + { + foreach (var sourceGenericType in sourceClass.GenericTypes) + { + await AddMissingUsingStatementsAsync(sourceGenericType); + } + } + if (sourceClass.HasAttributes) + { + foreach (var classAttribute in sourceClass.Attributes) + { + await AddMissingUsingStatementsAsync(classAttribute); + } + } + if (sourceClass.Properties.Any()) + { + foreach (var classProperty in sourceClass.Properties) + { + await AddMissingUsingStatementsAsync(classProperty); + } + } + if (sourceClass.Methods.Any()) + { + foreach (var classMethod in sourceClass.Methods) + { + await AddMissingUsingStatementsAsync(classMethod); + } + } + if (sourceClass.Fields.Any()) + { + foreach (var classField in sourceClass.Fields) + { + await AddMissingUsingStatementsAsync(classField); + } + } + if(sourceClass.Events.Any()) + { + foreach (var classEvent in sourceClass.Events) + { + await AddMissingUsingStatementsAsync(classEvent); + } + } + + if(sourceClass.NestedClasses.Any()) + { + foreach (var nestedClass in sourceClass.NestedClasses) + { + await AddMissingUsingStatementsAsync(nestedClass); + } + } + + if(sourceClass.NestedStructures.Any()) + { + foreach (var nestedStructure in sourceClass.NestedStructures) + { + await AddMissingUsingStatementsAsync(nestedStructure); + } + } + + if(sourceClass.NestedInterfaces.Any()) + { + foreach (var nestedInterface in sourceClass.NestedInterfaces) + { + await AddMissingUsingStatementsAsync(nestedInterface); + } + } + } + + + /// + /// Analyzes the specified method and adds any missing using statements required for its types, attributes, and + /// parameters to ensure proper compilation. + /// + /// This method recursively processes the method's generic types, attributes, parameters, + /// and return type to identify and add any necessary using statements. It ensures that all referenced types + /// and attributes are properly resolved in the context of the source code. + /// The method to analyze for missing using statements. Cannot be . + /// A that represents the asynchronous operation. + private async Task AddMissingUsingStatementsAsync(CsMethod sourceMethod) + { + if (sourceMethod == null) return; + + if (sourceMethod.HasStrongTypesInGenerics) + { + foreach (var sourceGenericType in sourceMethod.GenericTypes) + { + await AddMissingUsingStatementsAsync(sourceGenericType); + } + } + + if (sourceMethod.HasAttributes) + { + foreach (var methodAttributes in sourceMethod.Attributes) + { + await AddMissingUsingStatementsAsync(methodAttributes); + } + } + + if (sourceMethod.HasParameters) + { + foreach (var sourceMethodParameter in sourceMethod.Parameters) + { + if(sourceMethodParameter.HasAttributes) + { + foreach (var parameterAttribute in sourceMethodParameter.Attributes) + { + await AddMissingUsingStatementsAsync(parameterAttribute); + } + } + await AddMissingUsingStatementsAsync(sourceMethodParameter.ParameterType); + } + } + + if (sourceMethod.ReturnType != null) await AddMissingUsingStatementsAsync(sourceMethod.ReturnType); + } + + /// + /// Adds the necessary using statements for the specified source property and its related types. + /// + /// The source property for which missing using statements will be added. This parameter cannot be . + public async Task AddMissingUsingStatementsAsync(CsProperty sourceProperty) + { + if (sourceProperty == null) return; + + if (sourceProperty.HasAttributes) + { + foreach (var methodAttributes in sourceProperty.Attributes) + { + await AddMissingUsingStatementsAsync(methodAttributes); + } + } + + await AddMissingUsingStatementsAsync(sourceProperty.PropertyType); + } + + /// + /// Adds any missing using statements required for the specified event and its related types. + /// + /// This method recursively processes the event's attributes and event type to ensure all + /// necessary using statements are added. If is , the + /// method returns without performing any action. + /// The event for which missing using statements should be added. Cannot be . + public async Task AddMissingUsingStatementsAsync(CsEvent sourceEvent) + { + if (sourceEvent == null) return; + + if (sourceEvent.HasAttributes) + { + foreach (var methodAttributes in sourceEvent.Attributes) + { + await AddMissingUsingStatementsAsync(methodAttributes); + } + } + + await AddMissingUsingStatementsAsync(sourceEvent.EventType); + } + + /// + /// Adds the necessary using statements for the specified field and its related attributes or data types. + /// + /// This method processes the field's attributes and data type recursively to ensure all + /// required using statements are included. + /// The field for which missing using statements should be added. Cannot be . + private async Task AddMissingUsingStatementsAsync(CsField sourceField) + { + if (sourceField == null) return; + + + if (sourceField.HasAttributes) + { + foreach (var methodAttributes in sourceField.Attributes) + { + await AddMissingUsingStatementsAsync(methodAttributes); + } + } + + await AddMissingUsingStatementsAsync(sourceField.DataType); + } + + /// + /// Adds the necessary using statements for the specified attribute asynchronously. + /// + /// This method ensures that the required using statements for the provided attribute's + /// type are added. If is , the method returns without + /// performing any action. + /// The attribute for which missing using statements should be added. Cannot be . + private async Task AddMissingUsingStatementsAsync(CsAttribute sourceAttribute) + { + if (sourceAttribute == null) return; + + await AddMissingUsingStatementsAsync(sourceAttribute.Type); + } + + /// + /// Adds missing using statements for the specified type and its generic type arguments, if applicable. + /// + /// This method recursively processes generic type arguments of the specified type to + /// ensure all necessary using statements are added. If the namespace of the type is mapped to a different + /// target namespace, the mapped namespace is used. + /// The source type for which to add missing using statements. This includes processing its namespace and any + /// generic type arguments. + private async Task AddMissingUsingStatementsAsync(CsType sourceType) + { + if (sourceType == null) return ; + + if (sourceType.IsGenericPlaceHolder) return ; + + if (sourceType.HasStrongTypesInGenerics) + { + foreach (var sourceTypeGenericType in sourceType.GenericTypes) + { + await AddMissingUsingStatementsAsync(sourceTypeGenericType); + } + } + + string targetNamespace = MappedNamespaces.FirstOrDefault(m => m.Source == sourceType.Namespace)?.Destination; + + targetNamespace ??= sourceType.Namespace; + + var validate = NamespaceManager.ValidNameSpace(targetNamespace); + + if (!validate.namespaceFound) await UsingStatementAddAsync(targetNamespace); + + } + + + /// + /// Adds a namespace to the current context, optionally with an alias, if it is not already present. + /// + /// If the specified namespace is already present, no action is taken. The method + /// validates the namespace before attempting to add it. This method does not perform any asynchronous + /// operations despite returning a . + /// The namespace to add. This value cannot be null, empty, or consist only of whitespace. + /// An optional alias for the namespace. If provided, the namespace will be added with the specified alias. If + /// null, the namespace will be added without an alias. + /// A completed representing the asynchronous operation. + public Task UsingStatementAddAsync(string nameSpace, string alias = null) + { + if (string.IsNullOrWhiteSpace(nameSpace)) return Task.CompletedTask; + + + var validate = _namespaceManager.ValidNameSpace(nameSpace); + + if(!validate.namespaceFound) + { + if (alias == null) + { + _namespaceManager = _namespaceManager.AddNamespace(nameSpace); + } + else + { + _namespaceManager = _namespaceManager.AddNamespace(nameSpace, alias); + } + } + + return Task.CompletedTask; + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsInterfaceExtensions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsInterfaceExtensions.cs new file mode 100644 index 0000000..3719b9c --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsInterfaceExtensions.cs @@ -0,0 +1,88 @@ +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Static class that provides extension methods for the class. + /// + public static class CsInterfaceExtensions + { + /// + /// Retrieves all unique methods defined in the interface and its inherited interfaces. + /// + /// This method ensures that duplicate methods, based on their comparison hash code, are + /// excluded from the result. It recursively traverses all inherited interfaces to collect their methods as + /// well. + /// The interface from which to retrieve the methods. Cannot be . + /// A list of objects representing all unique methods defined in the interface and its + /// inherited interfaces. If the is , an empty list is returned. + public static List GetAllInterfaceMethods(this CsInterface source) + { + var result = new List(); + + if (source == null) return result; + + if (source.Methods.Any()) + { + foreach (var method in source.Methods) + { + var currentMethodHash = method.GetComparisonHashCode(); + + if (result.Any(m => m.GetComparisonHashCode() == currentMethodHash)) continue; + result.Add(method); + } + } + if (source.InheritedInterfaces.Any()) + { + foreach (var inheritedInterface in source.InheritedInterfaces) + { + var inheritedMethods = inheritedInterface.GetAllInterfaceMethods(); + if (inheritedMethods.Any()) + { + foreach (var method in inheritedMethods) + { + var currentMethodHash = method.GetComparisonHashCode(); + + if (result.Any(m => m.GetComparisonHashCode() == currentMethodHash)) continue; + result.Add(method); + } + } + } + } + + return result; + } + + /// + /// Extension method that generates the fully qualified type name of the specified interface, including its namespace and generic + /// parameters if applicable. + /// + /// The instance representing the interface for which the fully qualified type name is + /// generated. Must not be and must be loaded. + /// An optional instance used to resolve and append namespaces. If , a default will be used. + /// An optional list of objects used to map namespaces during the generation of the + /// type name. If , no namespace mapping will be applied. + /// A representing the fully qualified type name of the interface, including its namespace + /// and generic parameters if applicable. Returns if is or not loaded. + public static string GenerateInterfaceFullTypeName(this CsInterface source, NamespaceManager manager = null, + List mappedNamespaces = null) + { + if (source == null || !source.IsLoaded) return null; + + StringBuilder stringBuilder = new StringBuilder(); + NamespaceManager nsManager = manager ?? new NamespaceManager(); + string str = nsManager.AppendingNamespace(source.Namespace); + stringBuilder.Append(str == null ? source.Name : str + "." + source.Name); + if (source.IsGeneric) + stringBuilder.Append(source.GenericParameters.GenerateCSharpGenericParametersSignature(manager, mappedNamespaces)); + return stringBuilder.ToString(); + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsInterfaceResult.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsInterfaceResult.cs new file mode 100644 index 0000000..a28c29a --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsInterfaceResult.cs @@ -0,0 +1,86 @@ +using CodeFactory.WinVs.Factory; +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Represents the result of processing a C# interface, including its name, status, source, and the resulting + /// interface object. + /// + /// This class provides information about the outcome of processing a C# interface, such as + /// whether it was created, updated, or skipped. It also includes methods for updating the result with new data and + /// validating the result to ensure it is complete and ready for further processing. + public class CsInterfaceResult :CsSourceResult + { + /// + /// The name of the interface that was processed. + /// + public required string InterfaceName { get; init; } + + /// + /// The interface that was created or updated. + /// + public CsInterface Interface { get; init; } + + /// + /// Updates the current interface result with an updated interface result. Use this to merge a 'created' result with an 'updated' result so it returns 'created' but with the most recent source code + /// + /// The updated interface result + public CsInterfaceResult UpdateWith(CsInterfaceResult updatedResult) + { + if (updatedResult == null) + return this; + + ResultStatusType status; + + if (Status == ResultStatusType.Created) + { + status = ResultStatusType.Created; + } + else if (updatedResult.Status == ResultStatusType.Skipped) + { + status = updatedResult.Status; + } + else + { + status = updatedResult.Status; + } + + return new CsInterfaceResult + { + InterfaceName = updatedResult.InterfaceName, + Status = status, + Source = updatedResult.Source, + Interface = updatedResult.Interface + }; + } + + + /// + /// Validates the current interface result to ensure that the source and interface are not null. This is used to ensure that the result is valid before further processing. + /// + /// The name of the method that called the validation. + /// Raised if the source or the interface is null. + public override void ValidateResult([CallerMemberName] string callerName = null) + { + string interfaceDescriptor = string.Empty; + if (Status == ResultStatusType.Created) + interfaceDescriptor = "newly created "; + else if (Status == ResultStatusType.Updated) + interfaceDescriptor = "updated "; + else if (Status == ResultStatusType.Skipped) + interfaceDescriptor = ""; + + if (Source == null) + throw new CodeFactoryException($"Failed to load source for {interfaceDescriptor}'{InterfaceName}', cannot complete {callerName}."); + if (Interface == null) + throw new CodeFactoryException($"Failed to load class for {interfaceDescriptor}'{InterfaceName}', cannot complete {callerName}."); + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsRecordResult.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsRecordResult.cs new file mode 100644 index 0000000..a4597b7 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsRecordResult.cs @@ -0,0 +1,88 @@ +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Represents the result of processing a C# record, including its name, status, source, and the resulting record + /// object. + /// + /// This class is used to encapsulate the outcome of processing a C# record, such as whether it + /// was created, updated, or skipped. It provides methods to update the result with new information and to validate + /// the integrity of the result. + public class CsRecordResult : CsSourceResult + { + /// + /// The name of the record that was processed. + /// + public required string RecordName { get; init; } + + /// + /// The record that was created or updated. + /// + public required CsRecord Record { get; init; } + + + /// + /// Updates the current record result with an updated record result. Use this to merge a 'created' result with an 'updated' result so it returns 'created' but with the most recent source code + /// + /// The updated record result + /// + public CsRecordResult UpdateWith(CsRecordResult updatedResult) + { + if (updatedResult == null) + return this; + + ResultStatusType status; + + if (Status == ResultStatusType.Created) + { + status = ResultStatusType.Created; + } + else if (updatedResult.Status == ResultStatusType.Skipped) + { + status = updatedResult.Status; + } + else + { + status = updatedResult.Status; + } + + return new CsRecordResult + { + RecordName = updatedResult.RecordName, + Status = status, + Source = updatedResult.Source, + Record = updatedResult.Record + }; + } + + /// + /// Validates the result of the record result. This checks to ensure that the source and record are not null and throws an exception if they are. + /// + /// The method name that called the validation. + /// + /// Raised if the source or the record models are null. + public override void ValidateResult([CallerMemberName] string callerName = null) + { + string classDescriptor = string.Empty; + if (Status == ResultStatusType.Created) + classDescriptor = "newly created "; + else if (Status == ResultStatusType.Updated) + classDescriptor = "updated "; + else if (Status == ResultStatusType.Skipped) + classDescriptor = ""; + + if (Source == null) + throw new CodeFactoryException($"Failed to load source for {classDescriptor}'{RecordName}', cannot complete {callerName}."); + if (Record == null) + throw new CodeFactoryException($"Failed to load record for {classDescriptor}'{RecordName}', cannot complete {callerName}."); + + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceClassManager.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceClassManager.cs new file mode 100644 index 0000000..ed66239 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceClassManager.cs @@ -0,0 +1,250 @@ + +using CodeFactory.WinVs.Models.CSharp; +using CodeFactory.WinVs.Stats; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Provides functionality for managing C# class source code, including adding syntax elements and ensuring + /// necessary using statements are present. + /// + /// This class extends to provide specialized + /// operations for managing C# class definitions (). It supports adding syntax before or after + /// fields and constructors, as well as ensuring that all required using statements are included in the source + /// code. + public class CsSourceClassManager : CsSourceContainerManager + { + /// + /// Initializes a new instance of the class. + /// + /// The source object representing the C# source code to be managed. + /// The container class associated with the source code. + /// The factory management instance used for managing dependencies or related operations. + public CsSourceClassManager(CsSource source, CsClass container,ICsFactoryManagement factoryManagement) : base(source, container, factoryManagement) + { + // Intentionally blank + } + + + + /// + /// Adds the provided syntax before the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task FieldsAddBeforeAsync(string syntax) + { + await FieldsAddBeforeTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax before the field definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task FieldsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Fields.Any(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource)) + { + var fieldData = container.Fields.First(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource); + + var updatedSource = await fieldData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.ContainerAddToBeginningTransactionAsync(syntax); + } + + return result; + } + + /// + /// Adds the provided syntax after the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task FieldsAddAfterAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + if (container.Fields.Any(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource)) + { + var fieldData = container.Fields.Last(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource); + + var updatedSource = await fieldData.AddAfterAsync(syntax); + + if (updatedSource == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.GetModel(ContainerPath); + + UpdateSources(updatedSource, updatedContainer); + } + else + { + await this.ContainerAddToBeginningAsync(syntax); + } + } + + /// + /// Adds the provided syntax after the field definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task FieldsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Fields.Any(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource)) + { + var fieldData = container.Fields.Last(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource); + + var updatedSource = await fieldData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.ContainerAddToBeginningTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax before the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task ConstructorsAddBeforeAsync(string syntax) + { + await ConstructorsAddBeforeTransactionAsync(syntax); + } + + /// + /// Add the provided syntax before the constructor definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task ConstructorsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + if (container.Constructors.Any(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource)) + { + var constData = container.Constructors.First(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource); + + var updatedSource = await constData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.FieldsAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax after the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task ConstructorsAddAfterAsync(string syntax) + { + await ConstructorsAddAfterTransactionAsync(syntax); + } + + /// + /// Add the provided syntax after the constructor definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task ConstructorsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Constructors.Any(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource)) + { + var constData = container.Constructors.Last(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource); + + var updatedSource = await constData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.FieldsAddAfterTransactionAsync(syntax); + } + + return result; + } + + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceContainerManager.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceContainerManager.cs new file mode 100644 index 0000000..dc0d5fc --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceContainerManager.cs @@ -0,0 +1,2027 @@ +using CodeFactory.WinVs.Models.CSharp; +using CodeFactory.WinVs.Models.CSharp.Builder; +using CodeFactory.WinVs.Stats; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Provides an abstract base class for managing the relationship between a source file and its associated + /// container, along with Visual Studio actions and namespace management. + /// + /// This class offers a comprehensive set of methods for manipulating source files and their + /// associated containers, including adding, removing, and replacing syntax elements, managing namespaces, and + /// handling nested types. It also integrates with Visual Studio-specific actions and utilities through the interface. + /// The type of the container associated with the source file. Must inherit from . + public abstract class CsSourceContainerManager : ICsSourceContainerManager where TContainerType : CsContainer + { + //Backing fields for properties. + private CsSource _source; + private TContainerType _container; + private readonly ICsFactoryManagement _factoryManagement; + + /// + /// Lookup path used for loading the container from the source. + /// + protected readonly string ContainerPath; + + /// + /// Initializes a new instance of the class with the + /// specified source, container, and factory management. + /// + /// The source object that provides the context for this container manager. + /// The container associated with this manager. Can be if no container is provided. + /// The factory management instance used to manage dependencies and operations. Cannot be . + /// Thrown if is . + protected CsSourceContainerManager(CsSource source, TContainerType container, ICsFactoryManagement factoryManagement) + { + _source = source; + _container = container; + + if (_container != null) ContainerPath = container.LookupPath; + + _factoryManagement = factoryManagement ?? throw new ArgumentNullException(nameof(factoryManagement)); + } + + /// + /// Target source that is being updated. + /// + public CsSource Source => _source; + + /// + /// Target container being updated. + /// + public TContainerType Container => _container; + + /// + /// The code factory actions for visual studio to be used with updates to the source. + /// + public IVsActions VsActions => _factoryManagement.VsActions; + + + /// + /// The namespace manager that is used for updating source. + /// + public NamespaceManager NamespaceManager => _factoryManagement.NamespaceManager; + + /// + /// Mapped namespaces used for model moving from a source to a new target. + /// + public IReadOnlyList MappedNamespaces => _factoryManagement.MappedNamespaces; + + /// + /// Updates the source and container associated with the current instance. + /// + /// The source object to associate with this instance. Cannot be . + /// The container object to associate with this instance. Cannot be . + /// Thrown if or is . + public void UpdateSources(CsSource source, TContainerType container = null) + { + _source = source ?? throw new ArgumentNullException(nameof(source)); + + + _container = container ?? source.GetModel(ContainerPath); + + } + + /// + /// Checks all types definitions for the loaded container if the container is not loaded will not add missing using statements. + /// + public async Task AddMissingUsingStatementsAsync() + { + if (Container == null) return; + + await UpdateNamespaceManager(Container); + } + + /// + /// Updates the source code by adding missing using statements based on the provided namespace manager. + /// + /// This method compares the using statements defined in the namespace manager with the + /// current namespace references in the source code. If any using statements are missing, they are added to the + /// source. + /// A task that represents the asynchronous operation of updating the using statements. + public async Task UpdateUsingStatementsInSource() + { + if (Container == null) return; + + var usingStatements = NamespaceManager.UsingStatements; + + if (usingStatements == null || !usingStatements.Any()) return; + + + var currentNamespaces = Source.NamespaceReferences; + + if (currentNamespaces == null) return; + + + var createUsingStatements = new List(); + + foreach (var usingStatement in usingStatements) + { + //Check if the using statement is already present in the source. + if (currentNamespaces.Any(n => n.ReferenceNamespace == usingStatement.ReferenceNamespace && n.Alias == usingStatement.Alias)) + { + continue; // Skip if already present + } + + createUsingStatements.Add(usingStatement); + } + + if (!createUsingStatements.Any()) return; + + foreach (var usingStatement in createUsingStatements) + { + // Add the using statement to the source + _source = await Source.AddUsingStatementAsync(usingStatement.ReferenceNamespace, usingStatement.Alias); + } + } + + /// + /// Adds the provided syntax to the beginning of the source file. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task SourceAddToBeginningAsync(string syntax) + { + await SourceAddToBeginningTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax to the beginning of the source file and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task SourceAddToBeginningTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + + var updatedSource = await source.AddToBeginningTransactionAsync(syntax); + + if (updatedSource == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Adds the provided syntax to the end of the source file. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task SourceAddToEndAsync(string syntax) + { + await SourceAddToEndTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax to the end of the source file and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task SourceAddToEndTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + + var updatedSource = await source.AddToEndTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource?.Transaction; + } + + /// + /// Adds the provided syntax before the containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task ContainerAddBeforeAsync(string syntax) + { + await ContainerAddBeforeTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax before the containers definition and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task ContainerAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var updatedSource = await container.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource?.Transaction; + } + /// + /// Adds the provided syntax after containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task ContainerAddAfterAsync(string syntax) + { + await ContainerAddAfterTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax after containers definition and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task ContainerAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var updatedSource = await container.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Adds the provided syntax to the beginning of the containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task ContainerAddToBeginningAsync(string syntax) + { + await ContainerAddToBeginningTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax to the beginning of the containers definition and returns the details of the transaction.q + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task ContainerAddToBeginningTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var updatedSource = await container.AddToBeginningTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Adds the provided syntax to the end of the containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task ContainerAddToEndAsync(string syntax) + { + await ContainerAddToEndTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax to the end of the containers definition and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task ContainerAddToEndTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var updatedSource = await container.AddToEndTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Adds the provided syntax before the first using statement definition. + /// + /// Target syntax to be added + /// Thrown if either the source or the container is null after updating. + public async Task UsingStatementsAddBeforeAsync(string syntax) + { + await UsingStatementsAddBeforeTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax before the first using statement definition and returns the details of the transaction. + /// + /// Target syntax to be added + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task UsingStatementsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + + CsSourceTransaction updatedSource = null; + + var sourceDoc = source.SourceDocument; + if (source.NamespaceReferences.Any(n => n.SourceDocument == sourceDoc & n.LoadedFromSource)) + { + var usingStatement = source.NamespaceReferences.First(n => n.SourceDocument == sourceDoc & n.LoadedFromSource); + + updatedSource = await usingStatement.AddBeforeTransactionAsync(syntax); + } + else + { + updatedSource = await source.AddToBeginningTransactionAsync(syntax); + } + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Adds the provided syntax before the first using statement definition. + /// + /// Target syntax to be added + /// Thrown if either the source or the container is null after updating. + public async Task UsingStatementsAddAfterAsync(string syntax) + { + await UsingStatementsAddAfterTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax before the first using statement definition and returns the details of the transaction. + /// + /// Target syntax to be added + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task UsingStatementsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + + CsSourceTransaction updatedSource = null; + + var sourceDoc = source.SourceDocument; + + if (source.NamespaceReferences.Any(n => n.SourceDocument == sourceDoc & n.LoadedFromSource)) + { + var usingStatement = source.NamespaceReferences.Last(n => n.SourceDocument == sourceDoc & n.LoadedFromSource); + + updatedSource = await usingStatement.AddAfterTransactionAsync(syntax); + } + else + { + updatedSource = await source.AddToBeginningTransactionAsync(syntax); + } + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Adds the provided syntax before the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public abstract Task FieldsAddBeforeAsync(string syntax); + + /// + /// Adds the provided syntax before the field definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public abstract Task FieldsAddBeforeTransactionAsync(string syntax); + + + /// + /// Adds the provided syntax after the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public abstract Task FieldsAddAfterAsync(string syntax); + + /// + /// Adds the provided syntax after the field definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public abstract Task FieldsAddAfterTransactionAsync(string syntax); + + + /// + /// Add the provided syntax before the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public abstract Task ConstructorsAddBeforeAsync(string syntax); + + /// + /// Add the provided syntax before the constructor definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public abstract Task ConstructorsAddBeforeTransactionAsync(string syntax); + + + /// + /// Add the provided syntax after the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public abstract Task ConstructorsAddAfterAsync(string syntax); + + /// + /// Add the provided syntax after the constructor definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public abstract Task ConstructorsAddAfterTransactionAsync(string syntax); + + + /// + /// Add the provided syntax before the property definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task PropertiesAddBeforeAsync(string syntax) + { + await PropertiesAddBeforeTransactionAsync(syntax); + + } + + /// + /// Add the provided syntax before the property definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task PropertiesAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Properties.Any(p => p.ModelSourceFile == sourceDoc & p.LoadedFromSource)) + { + var propertyData = container.Properties.First(p => p.ModelSourceFile == sourceDoc & p.LoadedFromSource); + + var updatedSource = await propertyData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.ConstructorsAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax after the property definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task PropertiesAddAfterAsync(string syntax) + { + await PropertiesAddAfterTransactionAsync(syntax); + } + + /// + /// Add the provided syntax after the property definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task PropertiesAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Properties.Any(p => p.ModelSourceFile == sourceDoc & p.LoadedFromSource)) + { + var propertyData = container.Properties.Last(p => p.ModelSourceFile == sourceDoc & p.LoadedFromSource); + + var updatedSource = await propertyData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.ConstructorsAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax before the event definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task EventsAddBeforeAsync(string syntax) + { + await EventsAddBeforeTransactionAsync(syntax); + } + + /// + /// Add the provided syntax before the event definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task EventsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Events.Any(e => e.ModelSourceFile == sourceDoc & e.LoadedFromSource)) + { + var eventData = container.Events.First(e => e.ModelSourceFile == sourceDoc & e.LoadedFromSource); + + var updatedSource = await eventData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.PropertiesAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax after the event definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task EventsAddAfterAsync(string syntax) + { + await EventsAddAfterTransactionAsync(syntax); + } + + /// + /// Add the provided syntax after the event definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task EventsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Events.Any(e => e.ModelSourceFile == sourceDoc & e.LoadedFromSource)) + { + var eventData = container.Events.Last(e => e.ModelSourceFile == sourceDoc & e.LoadedFromSource); + + var updatedSource = await eventData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.PropertiesAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax before the method definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task MethodsAddBeforeAsync(string syntax) + { + await MethodsAddBeforeTransactionAsync(syntax); + } + + /// + /// Add the provided syntax before the method definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task MethodsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + if (container.Methods.Any(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource)) + { + var methodData = container.Methods.First(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource); + + var updatedSource = await methodData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.EventsAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax after the method definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task MethodsAddAfterAsync(string syntax) + { + await MethodsAddAfterTransactionAsync(syntax); + } + + /// + /// Add the provided syntax after the method definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task MethodsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Methods.Any(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource)) + { + var methodData = container.Methods.Last(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource); + + var updatedSource = await methodData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.EventsAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the syntax before the target member. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task MemberAddBeforeAsync(CsMember member, string syntax) + { + await MemberAddBeforeTransactionAsync(member, syntax); + + } + + /// + /// Add the syntax before the target member and returns the details of the transaction. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task MemberAddBeforeTransactionAsync(CsMember member, string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + + if (member == null) throw new ArgumentNullException(nameof(member)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSourceTransaction updatedSource = null; + + var currentModel = this.Source.GetModel(member.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current member model for '{member.Name}' cannot add before the member."); + + + updatedSource = await currentModel.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Add the syntax after the target member. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task MemberAddAfterAsync(CsMember member, string syntax) + { + await MemberAddAfterTransactionAsync(member, syntax); + } + + /// + /// Add the syntax after the target member and returns the details of the transaction. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task MemberAddAfterTransactionAsync(CsMember member, string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + + if (member == null) throw new ArgumentNullException(nameof(member)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSourceTransaction updatedSource = null; + + var currentModel = this.Source.GetModel(member.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current member model for '{member.Name}' cannot add after the member."); + + + updatedSource = await currentModel.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Comments out member from the source container. + /// + /// Target member. + /// Optional parameters sets the syntax to use when commenting out the member. This will default to use '//' + /// Thrown if either the source or the container is null after updating. + public async Task MemberCommentOut(CsMember member, string commentSyntax = "//") + { + if (string.IsNullOrEmpty(commentSyntax)) return; + + if (member == null) throw new ArgumentNullException(nameof(member)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSource updatedSource = null; + + var currentModel = this.Source.GetModel(member.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current member model for '{member.Name}' cannot comment out the member."); + + + updatedSource = await currentModel.CommentOutSyntaxAsync(commentSyntax); + + if (updatedSource == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.GetModel(ContainerPath); + + UpdateSources(updatedSource, updatedContainer); + } + + /// + /// Syntax replaces the target member. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task MemberReplaceAsync(CsMember member, string syntax) + { + await MemberReplaceTransactionAsync(member, syntax); + } + + /// + /// Syntax replaces the target member and returns the details of the transaction. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task MemberReplaceTransactionAsync(CsMember member, string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + + if (member == null) throw new ArgumentNullException(nameof(member)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSourceTransaction updatedSource = null; + + var currentModel = this.Source.GetModel(member.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current member model for '{member.Name}' cannot replace the member."); + + updatedSource = await currentModel.ReplaceTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Removes the target member. + /// + /// Target member. + /// Thrown if either the source or the container is null after updating. + public async Task MemberRemoveAsync(CsMember member) + { + if (member == null) throw new ArgumentNullException(nameof(member)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSource updatedSource = null; + + var currentModel = this.Source.GetModel(member.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current member model for '{member.Name}' cannot remove the member."); + + + updatedSource = await currentModel.DeleteAsync(); + + if (updatedSource == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.GetModel(ContainerPath); + + UpdateSources(updatedSource, updatedContainer); + } + + /// + /// Add the provided syntax before the nested enumeration definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task NestedEnumAddBeforeAsync(string syntax) + { + await NestedEnumAddBeforeTransactionAsync(syntax); + } + + /// + /// Add the provided syntax before the nested enumeration definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task NestedEnumAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container as CsContainerWithNestedContainers ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + if (container.NestedEnums.Any(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource)) + { + var enumData = container.NestedEnums.First(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource); + + var updatedSource = await enumData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.MethodsAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax after the nested enumeration definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task NestedEnumAddAfterAsync(string syntax) + { + await NestedEnumAddAfterTransactionAsync(syntax); + } + + /// + /// Add the provided syntax after the nested enumeration definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task NestedEnumAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container as CsContainerWithNestedContainers ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.NestedEnums.Any(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource)) + { + var enumData = container.NestedEnums.Last(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource); + + var updatedSource = await enumData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.MethodsAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Removes the nested enumeration. + /// + /// The target nested enumeration. + /// Thrown if either the source or the container is null after updating. + public async Task NestedEnumRemoveAsync(CsEnum nested) + { + if (nested == null) throw new ArgumentNullException(nameof(nested)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSource updatedSource = null; + + var currentModel = this.Source.GetModel(nested.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current Enum model for '{nested.Name}' cannot remove the nested eumeration."); + + + updatedSource = await currentModel.DeleteAsync(); + + if (updatedSource == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.GetModel(ContainerPath); + + UpdateSources(updatedSource, updatedContainer); + } + + /// + /// Replaces the nested enumeration with the provided syntax + /// + /// The target nested enumeration. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task NestedEnumReplaceAsync(CsEnum nested, string syntax) + { + await NestedEnumReplaceTransactionAsync(nested, syntax); + } + + /// + /// Replaces the nested enumeration with the provided syntax and returns the details of the transaction. + /// + /// The target nested enumeration. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task NestedEnumReplaceTransactionAsync(CsEnum nested, string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + if (nested == null) throw new ArgumentNullException(nameof(nested)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSourceTransaction updatedSource = null; + + var currentModel = this.Source.GetModel(nested.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current Enum model for '{nested.Name}' cannot replace the nested eumeration."); + + + updatedSource = await currentModel.ReplaceTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Add the provided syntax before the nested interface definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public async Task NestedInterfaceAddBeforeAsync(string syntax) + { + await NestedInterfaceAddBeforeTransactionAsync(syntax); + } + + /// + /// Add the provided syntax before the nested interface definitions and returns the details of the transaction. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public async Task NestedInterfaceAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container as CsContainerWithNestedContainers ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.NestedInterfaces.Any(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource)) + { + var interfaceData = container.NestedInterfaces.First(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource); + + var updatedSource = await interfaceData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.NestedEnumAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Adds a nested interface to the current context asynchronously after the specified syntax. + /// + /// The syntax after which the nested interface will be added. Cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task NestedInterfaceAddAfterAsync(string syntax) + { + await NestedInterfaceAddAfterTransactionAsync(syntax); + } + + /// + /// Adds the syntax after the nested interface definitions in the source code asynchronously and returns the details of the transaction. + /// + /// The syntax string representing the transaction to be added. Cannot be null or empty. + /// A object containing details of the transaction. Returns if the is null or empty. + /// Thrown if the source or container is not properly initialized, or if the updated source is null after the + /// operation. + public async Task NestedInterfaceAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container as CsContainerWithNestedContainers ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.NestedInterfaces.Any(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource)) + { + var interfaceData = container.NestedInterfaces.Last(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource); + + var updatedSource = await interfaceData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.NestedEnumAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Removes a nested interface from the source code asynchronously. + /// + /// This method removes the specified nested interface from the source code and updates + /// the source and container models accordingly. + /// The nested interface to be removed. Cannot be . + /// A task that represents the asynchronous operation. + /// Thrown if is or if the source or container is not + /// initialized. + /// Thrown if the current interface model for the specified nested interface cannot be retrieved. + public async Task NestedInterfaceRemoveAsync(CsInterface nested) + { + if (nested == null) throw new ArgumentNullException(nameof(nested)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSource updatedSource = null; + + var currentModel = this.Source.GetModel(nested.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current interface model for '{nested.Name}' cannot remove the nested interface."); + + + updatedSource = await currentModel.DeleteAsync(); + + if (updatedSource == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.GetModel(ContainerPath); + + UpdateSources(updatedSource, updatedContainer); + } + + /// + /// Replaces the syntax of a nested interface with the specified syntax. + /// + /// This method performs an asynchronous operation to update the syntax of a nested + /// interface. Ensure that the provided is valid for the intended use case. + /// The nested interface to be updated. Cannot be null. + /// The new syntax to replace the existing one. Cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task NestedInterfaceReplaceAsync(CsInterface nested, string syntax) + { + await NestedInterfaceReplaceTransactionAsync(nested, syntax); + } + + /// + /// Replaces a nested interface within the source code using the provided syntax and returns the details of the + /// transaction. + /// + /// This method performs a transactional replacement of a nested interface within the + /// source code. It updates the source and container models after the replacement is completed. + /// The nested interface to be replaced. Cannot be . + /// The new syntax to replace the nested interface with. Cannot be or empty. + /// A object containing the details of the replacement transaction, or if the is or empty. + /// Thrown if is , or if required internal dependencies are not + /// initialized. + /// Thrown if the current interface model for the specified nested interface cannot be retrieved. + public async Task NestedInterfaceReplaceTransactionAsync(CsInterface nested, string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + if (nested == null) throw new ArgumentNullException(nameof(nested)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSourceTransaction updatedSource = null; + + var currentModel = this.Source.GetModel(nested.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current interface model for '{nested.Name}' cannot replace the nested interface."); + + + updatedSource = await currentModel.ReplaceTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Adds a nested structure before the specified syntax asynchronously. + /// + /// The syntax string that specifies the location where the nested structure should be added. This parameter + /// cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task NestedStructuresAddBeforeAsync(string syntax) + { + await NestedStructuresAddBeforeTransactionAsync(syntax); + } + + /// + /// Adds a transaction to a nested structure before an existing transaction asynchronously. + /// + /// This method checks for existing nested structures associated with the source + /// document. If a matching structure is found, the transaction is added before the existing transaction. + /// Otherwise, the method delegates the operation to to + /// handle the addition. + /// The syntax string representing the transaction to be added. This value cannot be null or empty. + /// A object representing the details of the transaction that was added. Returns + /// if the parameter is null or empty. + /// Thrown if the source or container is not properly initialized, or if the updated source is null after + /// processing. + public async Task NestedStructuresAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container as CsContainerWithNestedContainers ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.NestedStructures.Any(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource)) + { + var structData = container.NestedStructures.First(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource); + + var updatedSource = await structData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.NestedInterfaceAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Adds a nested structure after the specified syntax asynchronously. + /// + /// The syntax after which the nested structure will be added. Cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task NestedStructuresAddAfterAsync(string syntax) + { + await NestedStructuresAddAfterTransactionAsync(syntax); + } + + /// + /// Adds a new transaction to the nested structures or interfaces within the container, based on the provided + /// syntax, and returns the details of the transaction. + /// + /// This method determines whether the transaction should be added to a nested structure + /// or a nested interface within the container. If a matching nested structure is found, the transaction is + /// added to it. Otherwise, the transaction is added to a nested interface. + /// The syntax string used to define the transaction to be added. This parameter cannot be null or empty. + /// A object containing the details of the transaction that was added. Returns + /// if the is null or empty. + /// Thrown if the source or container is not properly initialized, or if the updated source returned during the + /// operation is null. + public async Task NestedStructuresAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container as CsContainerWithNestedContainers ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.NestedStructures.Any(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource)) + { + var structData = container.NestedStructures.Last(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource); + + var updatedSource = await structData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.NestedInterfaceAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Removes a nested structure from the source and updates the container with the modified structure. + /// + /// This method performs the removal of a nested structure from the source, updates the + /// source with the changes, and refreshes the container to reflect the updated state. Ensure that the + /// Source and Container properties are properly initialized before calling this + /// method. + /// The nested structure to be removed. Cannot be . + /// A task that represents the asynchronous operation. + /// Thrown if is or if required dependencies such as the source + /// or container are not initialized. + /// Thrown if the current structure model for the specified nested structure cannot be retrieved. + public async Task NestedStructureRemoveAsync(CsStructure nested) + { + if (nested == null) throw new ArgumentNullException(nameof(nested)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSource updatedSource = null; + + var currentModel = this.Source.GetModel(nested.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current structure model for '{nested.Name}' cannot remove the nested structure."); + + updatedSource = await currentModel.DeleteAsync(); + + if (updatedSource == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.GetModel(ContainerPath); + + UpdateSources(updatedSource, updatedContainer); + } + + /// + /// Replaces the content of a nested structure with the specified syntax. + /// + /// This method performs an asynchronous operation to update the content of the provided + /// nested structure. Ensure that the parameter is a valid structure and that + /// contains the desired syntax for replacement. + /// The nested structure to be updated. Cannot be . + /// The new syntax to apply to the nested structure. Cannot be or empty. + /// A task that represents the asynchronous operation. + public async Task NestedStructureReplaceAsync(CsStructure nested, string syntax) + { + await NestedStructureReplaceTransactionAsync(nested, syntax); + } + + /// + /// Replaces a nested structure within the source code using the provided syntax and returns the details of the + /// transaction. + /// + /// This method performs a transactional replacement of a nested structure in the source + /// code. It updates the source and container models to reflect the changes made during the + /// transaction. + /// The nested structure to be replaced. Cannot be . + /// The new syntax to replace the nested structure with. Cannot be or empty. + /// A object containing details of the replacement transaction, or if the is or empty. + /// Thrown if is , or if required internal dependencies are not + /// initialized. + /// Thrown if the current structure model for the specified nested structure cannot be retrieved. + public async Task NestedStructureReplaceTransactionAsync(CsStructure nested, string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + if (nested == null) throw new ArgumentNullException(nameof(nested)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSourceTransaction updatedSource = null; + + var currentModel = this.Source.GetModel(nested.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current structure model for '{nested.Name}' cannot replace the nested structure."); + + updatedSource = await currentModel.ReplaceTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Adds a nested class to the current context before a specified syntax element asynchronously. + /// + /// The syntax element before which the nested class will be added. Cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task NestedClassesAddBeforeAsync(string syntax) + { + await NestedClassesAddBeforeTransactionAsync(syntax); + } + + /// + /// Adds a transaction to a nested class or structure before performing the specified operation. + /// + /// This method attempts to locate a nested class within the container that matches the + /// source document and is loaded from the source. If such a class is found, the transaction is added before the + /// specified operation. If no matching nested class is found, the operation is delegated to . + /// The syntax string representing the operation to be performed. + /// A object containing details of the transaction. Returns if the is or empty. + /// Thrown if the source or container is not properly initialized, or if the updated source is null after the + /// operation. + public async Task NestedClassesAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container as CsContainerWithNestedContainers ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.NestedClasses.Any(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource)) + { + var classData = container.NestedClasses.First(m => m.ModelSourceFile == sourceDoc & m.LoadedFromSource); + + var updatedSource = await classData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.NestedStructuresAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Adds a nested class to the current context after the specified syntax asynchronously. + /// + /// The syntax after which the nested class will be added. Cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task NestedClassesAddAfterAsync(string syntax) + { + await NestedClassesAddAfterTransactionAsync(syntax); + } + + /// + /// Adds a new nested class or structure to the container after a transaction, based on the provided syntax. + /// + /// This method determines whether the container already contains a nested class + /// associated with the current source document. If such a class exists, the method updates it by adding the + /// provided syntax after a transaction. Otherwise, it delegates the operation to to handle the addition as a nested + /// structure. + /// The syntax string representing the code to be added. This value cannot be null or empty. + /// A object containing details of the transaction. Returns if the is null or empty. + /// Thrown if the source or container is not properly initialized, or if the updated source is null after the + /// operation. + public async Task NestedClassesAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container as CsContainerWithNestedContainers ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.NestedClasses.Any(m => m.ModelSourceFile == sourceDoc)) + { + var classData = container.NestedClasses.Last(m => m.ModelSourceFile == sourceDoc); + + var updatedSource = await classData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.NestedStructuresAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Removes a nested class from the current container and updates the source and container models. + /// + /// This method removes the specified nested class from the source code and updates the + /// associated container model. Ensure that the _source and _container fields are properly + /// initialized before calling this method. + /// The nested class to be removed. Cannot be . + /// A task that represents the asynchronous operation. + /// Thrown if is , or if the source or container models are not + /// initialized. + /// Thrown if the current class model for the specified nested class cannot be retrieved. + public async Task NestedClassesRemoveAsync(CsClass nested) + { + if (nested == null) throw new ArgumentNullException(nameof(nested)); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + var currentModel = this.Source.GetModel(nested.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current class model for '{nested.Name}' cannot remove the nested class."); + + CsSource updatedSource = null; + + updatedSource = await currentModel.DeleteAsync(); + + if (updatedSource == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.GetModel(ContainerPath); + + UpdateSources(updatedSource, updatedContainer); + } + + /// + /// Replaces the content of a nested class with the specified syntax asynchronously. + /// + /// This method performs an asynchronous operation to update the content of a nested + /// class. Ensure that the provided is valid and compatible with the nested class + /// structure. + /// The nested class to be updated. Cannot be null. + /// The new syntax to replace the content of the nested class. Cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task NestedClassesReplaceAsync(CsClass nested, string syntax) + { + await NestedClassesReplaceTransactionAsync(nested, syntax); + } + + /// + /// Replaces a nested class within the source code using the provided syntax and returns the details of the + /// transaction. + /// + /// This method performs a transactional replacement of a nested class in the source + /// code. It ensures that the updated source and container models are synchronized after the + /// replacement. + /// The nested class to be replaced. Cannot be . + /// The new syntax to replace the nested class with. Cannot be or empty. + /// A object containing details of the replacement transaction, or if the is or empty. + /// Thrown if is or if required dependencies are not + /// initialized. + /// Thrown if the current class model for the specified nested class cannot be retrieved. + public async Task NestedClassesReplaceTransactionAsync(CsClass nested, string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + if (nested == null) throw new ArgumentNullException(nameof(nested)); + + var currentModel = this.Source.GetModel(nested.LookupPath); + if (currentModel == null) throw new CodeFactoryException($"Could not get the current class model for '{nested.Name}' cannot replace the nested class."); + + var source = _source ?? throw new ArgumentNullException(nameof(Source)); + var container = _container ?? throw new ArgumentNullException(nameof(Container)); + + CsSourceTransaction updatedSource = null; + + updatedSource = await currentModel.ReplaceTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + return updatedSource.Transaction; + } + + /// + /// Adds the specified syntax to the source or container at the specified injection location. + /// + /// This method determines the appropriate injection point based on the and performs the corresponding operation to add the syntax. The operation may target the + /// source, a container, or specific members such as fields, constructors, properties, methods, or nested + /// types. + /// The syntax to be added. Cannot be null or empty. + /// The specifying where the syntax should be injected. Must be a valid + /// enumeration value. + /// + /// Thrown if is null or empty, or if the required source or container is not + /// initialized. + /// Thrown if is not a valid value. + public async Task AddByInjectionLocationAsync(string syntax, InjectionLocation location) + { + if (string.IsNullOrEmpty(syntax)) return; + _ = _source ?? throw new ArgumentNullException(nameof(Source)); + _ = _container as CsContainerWithNestedContainers ?? throw new ArgumentNullException(nameof(Container)); + + switch (location) + { + case InjectionLocation.SourceBeginning: + await SourceAddToBeginningAsync(syntax); + break; + case InjectionLocation.SourceEnd: + await SourceAddToEndAsync(syntax); + break; + case InjectionLocation.ContainerBefore: + await ContainerAddBeforeAsync(syntax); + break; + case InjectionLocation.ContainerAfter: + await ContainerAddAfterAsync(syntax); + break; + case InjectionLocation.ContainerBeginning: + await ContainerAddToBeginningAsync(syntax); + break; + case InjectionLocation.ContainerEnd: + await ContainerAddToEndAsync(syntax); + break; + case InjectionLocation.FieldBefore: + await FieldsAddBeforeAsync(syntax); + break; + case InjectionLocation.FieldAfter: + await FieldsAddAfterAsync(syntax); + break; + case InjectionLocation.ConstructorBefore: + await ConstructorsAddBeforeAsync(syntax); + break; + case InjectionLocation.ConstructorAfter: + await ConstructorsAddAfterAsync(syntax); + break; + case InjectionLocation.PropertyBefore: + await PropertiesAddBeforeAsync(syntax); + break; + case InjectionLocation.PropertyAfter: + await PropertiesAddAfterAsync(syntax); + break; + case InjectionLocation.EventBefore: + await EventsAddBeforeAsync(syntax); + break; + case InjectionLocation.EventAfter: + await EventsAddAfterAsync(syntax); + break; + case InjectionLocation.MethodBefore: + await MethodsAddBeforeAsync(syntax); + break; + case InjectionLocation.MethodAfter: + await MethodsAddAfterAsync(syntax); + break; + case InjectionLocation.NestedEnumBefore: + await NestedEnumAddBeforeAsync(syntax); + break; + case InjectionLocation.NestedEnumAfter: + await NestedEnumAddAfterAsync(syntax); + break; + case InjectionLocation.NestedInterfaceBefore: + await NestedInterfaceAddBeforeAsync(syntax); + break; + case InjectionLocation.NestedInterfaceAfter: + await NestedInterfaceAddAfterAsync(syntax); + break; + case InjectionLocation.NestedStructureBefore: + await NestedStructuresAddBeforeAsync(syntax); + break; + case InjectionLocation.NestedStructureAfter: + await NestedStructuresAddAfterAsync(syntax); + break; + case InjectionLocation.NestedClassBefore: + await NestedClassesAddBeforeAsync(syntax); + break; + case InjectionLocation.NestedClassAfter: + await NestedClassesAddAfterAsync(syntax); + break; + default: + throw new ArgumentOutOfRangeException(nameof(location), location, null); + } + } + + + /// + /// Updates the collection of mapped namespaces used by the factory management system. + /// + /// This method updates the internal state of the factory management system with the + /// provided mapped namespaces. Ensure that the collection is not null and contains valid mappings before + /// calling this method. + /// A collection of objects representing the namespaces to be updated. Each namespace + /// in the collection will replace the existing mapped namespaces. + public void UpdateMappedNamespaces(IEnumerable mappedNamespaces) + { + _factoryManagement.UpdateMappedNamespaces(mappedNamespaces); + } + + /// + /// Updates the namespace manager with the provided model. + /// + /// The model containing the namespace configuration to be updated. + public async Task UpdateNamespaceManager(CsModel csModel) + { + await _factoryManagement.UpdateNamespaceManager(csModel); + } + + /// + /// Adds a using statement to the current context asynchronously. + /// + /// This method delegates the operation to an internal factory management component. + /// Ensure that the namespace provided is valid and does not conflict with existing using statements. + /// The namespace to be added as a using statement. This parameter cannot be or empty. + /// An optional alias for the namespace. If , no alias will be used. + public async Task UsingStatementAddAsync(string nameSpace, string alias = null) + { + await _factoryManagement.UsingStatementAddAsync(nameSpace, alias); + } + + /// + /// Asynchronously adds an attribute to the specified member using the provided syntax. + /// + /// The member to which the attribute will be added. Cannot be null. + /// The syntax string representing the attribute to add. Cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task MemberAddAttributeAsync(CsMember member, string syntax) + { + await MemberAddAttributeTransactionAsync(member, syntax); + } + + /// + /// Adds an attribute to the specified member and returns a transaction detail object representing what was performed. + /// + /// This method performs a transactional update to add an attribute to the specified + /// member. The operation updates the source model and ensures the changes are reflected in the internal + /// state. + /// The member to which the attribute will be added. Cannot be . + /// The syntax string representing the attribute to be added. This must be a valid attribute declaration. + /// A object representing the details of the completed transaction. + /// Thrown if is or if the updated source model is . + /// Thrown if the current member model cannot be retrieved for the specified . + public async Task MemberAddAttributeTransactionAsync(CsMember member, string syntax) + { + if (member == null) throw new ArgumentNullException(nameof(member)); + + var currentMember = _source.GetModel(member.LookupPath); + + if (currentMember == null) throw new CodeFactoryException($"Could not get the current member model for '{member.Name}' cannot add the attribute."); + + var docResult = await currentMember.AddAfterDocsTransactionAsync(syntax); + + _source = docResult?.Source ?? throw new ArgumentNullException(nameof(Source)); + + UpdateSources(_source); + + return docResult.Transaction; + } + + /// + /// Adds an attribute to the specified container asynchronously. + /// + /// This method performs the operation asynchronously and ensures that the attribute is + /// added to the specified container. The parameter should represent a valid attribute + /// declaration in the appropriate syntax format. + /// The container to which the attribute will be added. Cannot be null. + /// The syntax of the attribute to add. This must be a valid attribute syntax string. + /// A task that represents the asynchronous operation. + public async Task ContainerAddAttributeAsync(CsContainer container, string syntax) + { + await ContainerAddAttributeTransactionAsync(container, syntax); + } + + /// + /// Adds an attribute to the specified container and returns the details of the transaction that was performed. + /// + /// This method performs the addition of an attribute to the specified container and + /// updates the source model. The returned transaction details can be used to track the changes made during the + /// operation. + /// The container to which the attribute will be added. Cannot be . + /// The syntax of the attribute to add. Cannot be or empty. + /// The details of the transaction that added the attribute. + /// Thrown if is or if is or empty. + /// Thrown if the current container model cannot be retrieved for the specified . + public async Task ContainerAddAttributeTransactionAsync(CsContainer container, string syntax) + { + if (container == null) throw new ArgumentNullException(nameof(container)); + if (string.IsNullOrEmpty(syntax)) throw new ArgumentNullException(nameof(syntax)); + + var currentContainer = _source.GetModel(container.LookupPath) ?? throw new CodeFactoryException($"Could not get the current container model for '{container.Name}' cannot add the attribute."); + var containerResult = await currentContainer.AddAfterDocsTransactionAsync(syntax); + + UpdateSources(containerResult.Source ?? throw new ArgumentNullException(nameof(Source))); + + return containerResult?.Transaction; + } + + + /// + /// Adds a new attribute before the specified attribute in the source code asynchronously. + /// + /// The existing attribute before which the new attribute will be added. Cannot be null. + /// The syntax representation of the new attribute to be added. Cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task AttributeAddBeforeAsync(CsAttribute attribute, string syntax) + { + await AddBeforeTransactionAsync(attribute, syntax); + } + + /// + /// Adds the syntax before the specified attribute in the source code and returns the details of the transaction that was performed. + /// + /// Attribute to add before. + /// Syntax to be added. + /// The transaction details of the added syntax. + /// Thrown when required model or syntax data is missing. + public async Task AddBeforeTransactionAsync(CsAttribute attribute, string syntax) + { + //Bounds checking + if (attribute == null) throw new ArgumentNullException(nameof(attribute)); + if (string.IsNullOrEmpty(syntax)) throw new ArgumentNullException(nameof(syntax)); + + var updatedSource = await attribute.AddBeforeTransactionAsync(syntax); + UpdateSources(updatedSource.Source ?? throw new ArgumentNullException(nameof(updatedSource.Source))); + + return updatedSource.Transaction; + } + + /// + /// Adds syntax immediately after the specified attribute in the source code. + /// + /// This method performs the addition of a new attribute in an asynchronous manner. The + /// new attribute is inserted immediately after the specified in the source + /// code. + /// The existing attribute after which the new attribute will be added. Cannot be . + /// The syntax of the new attribute to be added. Cannot be or empty. + /// A task that represents the asynchronous operation. + public async Task AttributeAddAfterAsync(CsAttribute attribute, string syntax) + { + await AttributeAddAfterTransactionAsync(attribute, syntax); + } + + /// + /// Adds a specified sytnax after the attribute model definition and returns the transaction details. + /// + /// The attribute to add syntax after. Cannot be . + /// The syntax to be added. Cannot be or empty. + /// The representing the details of the transaction after the syntax is + /// added. + /// Thrown if is or if is or empty. + public async Task AttributeAddAfterTransactionAsync(CsAttribute attribute, string syntax) + { + if (attribute == null) throw new ArgumentNullException(nameof(attribute)); + if (string.IsNullOrEmpty(syntax)) throw new ArgumentNullException(nameof(syntax)); + + var updatedSource = await attribute.AddAfterTransactionAsync(syntax); + UpdateSources(updatedSource.Source ?? throw new ArgumentNullException(nameof(updatedSource.Source))); + + return updatedSource.Transaction; + } + + /// + /// Replaces the specified attribute with a new attribute defined by the provided syntax. + /// + /// The attribute to be replaced. Cannot be null. + /// The new attribute syntax to replace the existing attribute. Cannot be null or empty. + /// A task that represents the asynchronous operation. + public async Task ReplaceAttributeAsync(CsAttribute attribute, string syntax) + { + await ReplaceAttributeTransactionAsync(attribute, syntax); + } + + /// + /// Replaces the attribute in the source code with the provided syntax and returns the details of the transaction that was performed. + /// + /// The attribute to be replaced. Cannot be null. + /// The new attribute syntax to replace the existing attribute. Cannot be null or empty. + /// The representing the details of the transaction after the syntax replaces the attribute. + /// Thrown if is or if is or empty. + public async Task ReplaceAttributeTransactionAsync(CsAttribute attribute, string syntax) + { + if (attribute == null) throw new ArgumentNullException(nameof(attribute)); + if (string.IsNullOrEmpty(syntax)) throw new ArgumentNullException(nameof(syntax)); + + var updatedSource = await attribute.ReplaceTransactionAsync(syntax); + UpdateSources(updatedSource.Source ?? throw new ArgumentNullException(nameof(updatedSource.Source))); + + return updatedSource.Transaction; + } + + /// + /// Removes the specified attribute from the source code asynchronously. + /// + /// The attribute to be removed. Cannot be . + /// A task that represents the asynchronous operation. + /// Thrown if is or if the updated source is after the operation. + public async Task RemoveAttributeAsync(CsAttribute attribute) + { + if(attribute == null) throw new ArgumentNullException(nameof(attribute)); + + var updatedSource = await attribute.DeleteAsync(); + + UpdateSources(updatedSource ?? throw new ArgumentNullException(nameof(updatedSource))); + } + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceInterfaceManager.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceInterfaceManager.cs new file mode 100644 index 0000000..4d90429 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceInterfaceManager.cs @@ -0,0 +1,127 @@ +using CodeFactory.WinVs; +using CodeFactory.WinVs.Models.CSharp; +using CodeFactory.WinVs.Models.CSharp.Builder; +using CodeFactory.WinVs.Stats; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Provides functionality for managing source code representations of interfaces, including operations for adding + /// syntax elements and handling namespace mappings. + /// + /// This class extends to provide specialized + /// management for objects. It includes methods for adding syntax before or after + /// specific code elements, such as fields and constructors, and supports namespace management and Visual + /// Studio-specific actions. + public class CsSourceInterfaceManager : CsSourceContainerManager + { + + /// + /// Initializes a new instance of the class, which manages the + /// relationship between a source, an interface, and factory management. + /// + /// The source object that provides the data or functionality to be managed. + /// The interface container that this manager operates on. + /// The factory management instance used to handle dependencies or object creation. + + public CsSourceInterfaceManager(CsSource source, CsInterface container, CsFactoryManagement factoryManagement) : base(source, container, factoryManagement) + { + //Intentionally blank + } + + /// + /// Adds the provided syntax before the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task FieldsAddBeforeAsync(string syntax) + { + await FieldsAddBeforeTransactionAsync(syntax); + + } + + /// + /// Adds the provided syntax before the field definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task FieldsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + return await this.ContainerAddToBeginningTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax after the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task FieldsAddAfterAsync(string syntax) + { + await FieldsAddAfterTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax after the field definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task FieldsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + return await this.ContainerAddToBeginningTransactionAsync(syntax); + } + + /// + /// Add the provided syntax before the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task ConstructorsAddBeforeAsync(string syntax) + { + await ConstructorsAddBeforeTransactionAsync(syntax); + } + + /// + /// Add the provided syntax before the constructor definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task ConstructorsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + return await this.ContainerAddToBeginningTransactionAsync(syntax); + } + + /// + /// Add the provided syntax after the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task ConstructorsAddAfterAsync(string syntax) + { + await ConstructorsAddAfterTransactionAsync(syntax); + } + + /// + /// Add the provided syntax after the constructor definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task ConstructorsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + return await this.ContainerAddToBeginningTransactionAsync(syntax); + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceRecordManager.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceRecordManager.cs new file mode 100644 index 0000000..64bb217 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceRecordManager.cs @@ -0,0 +1,241 @@ +using CodeFactory.WinVs.Models.CSharp; +using CodeFactory.WinVs.Stats; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Provides functionality for managing C# source code associated with a container. + /// + /// This class extends to provide specialized + /// operations for handling C# records, including adding syntax before or after fields and constructors, and + /// ensuring that all necessary using statements are included in the source code. It integrates with Visual Studio + /// actions and supports namespace management. + public class CsSourceRecordManager : CsSourceContainerManager + { + /// + /// Initializes a new instance of the class. + /// + /// The source object that provides the data for this record manager. + /// The container object that holds the records managed by this instance. + /// The factory management instance used for creating and managing related objects. + public CsSourceRecordManager(CsSource source, CsRecord container, CsFactoryManagement factoryManagement) : base(source, container, factoryManagement) + { + //Intentionally blank + } + + /// + /// Adds the provided syntax before the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task FieldsAddBeforeAsync(string syntax) + { + await FieldsAddBeforeTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax before the field definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task FieldsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Fields.Any(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource)) + { + var fieldData = container.Fields.First(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource); + + var updatedSource = await fieldData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.ContainerAddToBeginningTransactionAsync(syntax); + } + + return result; + } + + /// + /// Adds the provided syntax after the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task FieldsAddAfterAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + if (container.Fields.Any(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource)) + { + var fieldData = container.Fields.Last(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource); + + var updatedSource = await fieldData.AddAfterAsync(syntax); + + if (updatedSource == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.GetModel(ContainerPath); + + UpdateSources(updatedSource, updatedContainer); + } + else + { + await this.ContainerAddToBeginningAsync(syntax); + } + } + + /// + /// Adds the provided syntax after the field definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task FieldsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Fields.Any(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource)) + { + var fieldData = container.Fields.Last(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource); + + var updatedSource = await fieldData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.ContainerAddToBeginningTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax before the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task ConstructorsAddBeforeAsync(string syntax) + { + await ConstructorsAddBeforeTransactionAsync(syntax); + } + + /// + /// Add the provided syntax before the constructor definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task ConstructorsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + if (container.Constructors.Any(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource)) + { + var constData = container.Constructors.First(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource); + + var updatedSource = await constData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.FieldsAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax after the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task ConstructorsAddAfterAsync(string syntax) + { + await ConstructorsAddAfterTransactionAsync(syntax); + } + + /// + /// Add the provided syntax after the constructor definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task ConstructorsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Constructors.Any(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource)) + { + var constData = container.Constructors.Last(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource); + + var updatedSource = await constData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.FieldsAddAfterTransactionAsync(syntax); + } + + return result; + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceResult.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceResult.cs new file mode 100644 index 0000000..3d12a8b --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceResult.cs @@ -0,0 +1,33 @@ +using CodeFactory.WinVs.Factory; +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Abstract base class for results from a factory. + /// + public abstract class CsSourceResult : ISourceResult where T : ISourceResult + { + /// + /// Gets the status of the result, indicating the outcome of the operation. + /// + public ResultStatusType Status { get; init; } + + /// + /// The source code model that was returned from the factory. + /// + public CsSource Source { get; init; } + + /// + /// Validates the results of the factory and returns the result. + /// + /// The name of the method that called the validation. + public abstract void ValidateResult([CallerMemberName] string callerName = null); + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceStructureManager.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceStructureManager.cs new file mode 100644 index 0000000..01eb95a --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSourceStructureManager.cs @@ -0,0 +1,227 @@ +using CodeFactory.WinVs; +using CodeFactory.WinVs.Models.CSharp; +using CodeFactory.WinVs.Models.CSharp.Builder; +using CodeFactory.WinVs.Stats; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Manages a structure in C# source code, providing functionality to modify and analyze the structural elements + /// of a source container, such as fields, properties, methods, and constructors. + /// + /// This class extends to provide specialized + /// operations for managing C# structures. It supports adding missing using statements, modifying fields and + /// constructors, and performing other structural updates. The class is designed to work with Visual Studio actions + /// and namespace management to ensure seamless integration with IDE-related operations. + public class CsSourceStructureManager : CsSourceContainerManager + { + /// + /// Initializes a new instance of the class. + /// + /// The source object representing the C# source code to be managed. Cannot be . + /// The container structure that holds the source code elements. Cannot be . + /// The factory management instance used for creating and managing related objects. Cannot be . + public CsSourceStructureManager(CsSource source, CsStructure container, CsFactoryManagement factoryManagement) : base(source, container,factoryManagement) + { + //Intentionally blank + } + + /// + /// Adds the provided syntax before the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task FieldsAddBeforeAsync(string syntax) + { + await FieldsAddBeforeTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax before the field definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task FieldsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Fields.Any(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource)) + { + var fieldData = container.Fields.First(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource); + + var updatedSource = await fieldData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.ContainerAddToBeginningTransactionAsync(syntax); + } + + return result; + } + + /// + /// Adds the provided syntax after the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task FieldsAddAfterAsync(string syntax) + { + await FieldsAddAfterTransactionAsync(syntax); + } + + /// + /// Adds the provided syntax after the field definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task FieldsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Fields.Any(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource)) + { + var fieldData = container.Fields.Last(f => f.ModelSourceFile == sourceDoc & f.LoadedFromSource); + + var updatedSource = await fieldData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + } + else + { + result = await this.ContainerAddToBeginningTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax before the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task ConstructorsAddBeforeAsync(string syntax) + { + await ConstructorsAddBeforeTransactionAsync(syntax); + } + + /// + /// Add the provided syntax before the constructor definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task ConstructorsAddBeforeTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Constructors.Any(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource)) + { + var constData = container.Constructors.First(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource); + + var updatedSource = await constData.AddBeforeTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.FieldsAddAfterTransactionAsync(syntax); + } + + return result; + } + + /// + /// Add the provided syntax after the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + public override async Task ConstructorsAddAfterAsync(string syntax) + { + await ConstructorsAddAfterTransactionAsync(syntax); + } + + /// + /// Add the provided syntax after the constructor definitions and returns the transaction details. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + public override async Task ConstructorsAddAfterTransactionAsync(string syntax) + { + if (string.IsNullOrEmpty(syntax)) return null; + var source = Source ?? throw new ArgumentNullException(nameof(Source)); + var container = Container ?? throw new ArgumentNullException(nameof(Container)); + + var sourceDoc = source.SourceDocument; + + TransactionDetail result = null; + + if (container.Constructors.Any(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource)) + { + var constData = container.Constructors.Last(c => c.ModelSourceFile == sourceDoc & c.LoadedFromSource); + + var updatedSource = await constData.AddAfterTransactionAsync(syntax); + + if (updatedSource?.Source == null) throw new ArgumentNullException(nameof(Source)); + + var updatedContainer = updatedSource.Source.GetModel(ContainerPath); + + UpdateSources(updatedSource.Source, updatedContainer); + + result = updatedSource.Transaction; + } + else + { + result = await this.FieldsAddAfterTransactionAsync(syntax); + } + + return result; + + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSyntaxBuilder.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSyntaxBuilder.cs new file mode 100644 index 0000000..9765478 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/CsSyntaxBuilder.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Base class for building syntax representations based on a specified request. + /// + /// Type of the syntax request that is passed in when building the syntax. + public abstract class CsSyntaxBuilder : ICsSyntaxBuilder where R : ISyntaxRequest + { + /// + /// Asynchronously builds a syntax representation of the specified request. + /// + /// The request object containing the data to be processed into a syntax representation. Cannot be null. + /// A task that represents the asynchronous operation. The task result contains the syntax representation as a + /// string. + public abstract Task BuildSyntaxAsync(R request); + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsFactoryManagement.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsFactoryManagement.cs new file mode 100644 index 0000000..6b5efe3 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsFactoryManagement.cs @@ -0,0 +1,69 @@ +using CodeFactory.WinVs; +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Defines the contract for managing C# factory-related operations, including namespace management, Visual Studio + /// interactions, and dynamic code generation tasks. + /// + /// This interface provides methods and properties for interacting with and managing namespaces, + /// updating namespace mappings, and performing Visual Studio-specific actions. It is designed to facilitate + /// operations within a C# factory context, such as dynamically adding using statements or managing namespace + /// mappings for code generation scenarios. + public interface ICsFactoryManagement + { + /// + /// Gets the Visual Studio actions interface, which provides methods and properties for interacting with Visual + /// Studio-specific functionality. + /// + IVsActions VsActions { get; } + + /// + /// Gets the instance used to track and manage namespaces within the C# factory context. + /// + NamespaceManager NamespaceManager { get; } + + /// + /// Mapped namespaces used for models moving from a source to a new target model. Maps the source namespaces to the target namespaces. + /// + IReadOnlyList MappedNamespaces { get; } + + /// + /// Updates the collection of mapped namespaces with the specified values. + /// + /// This method replaces the current collection of mapped namespaces with the provided + /// collection. If the input is , the collection is set to an empty, immutable + /// list. + /// A collection of objects representing the namespaces to be mapped. If is , the collection will be cleared. + void UpdateMappedNamespaces(IEnumerable mappedNamespaces); + + /// + /// Updates the namespace manager by adding any missing using statements for the specified model. + /// + /// This method determines the type of the provided and + /// processes it accordingly to ensure that all required using statements are added to the namespace manager. + /// If the model type is unsupported, the method performs no action. + /// The model to process. The model must not be and should represent a valid code + /// element, such as a type, attribute, field, property, method, event, or other supported model type. + /// + Task UpdateNamespaceManager(CsModel csModel); + + /// + /// Adds a using statement to the current context asynchronously. + /// + /// This method is typically used to dynamically add namespaces to a code generation or + /// scripting context. + /// The namespace to be added as a using statement. This cannot be null or empty. + /// An optional alias for the namespace. If provided, the using statement will include the alias. If null, the + /// namespace will be added without an alias. + /// A task that represents the asynchronous operation. + Task UsingStatementAddAsync(string nameSpace, string alias = null); + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsFactoryRequest.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsFactoryRequest.cs new file mode 100644 index 0000000..19d4a82 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsFactoryRequest.cs @@ -0,0 +1,21 @@ +using CodeFactory.WinVs.Factory.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Represents a request to the C# factory system, providing access to factory management operations such as Visual + /// Studio actions, namespace management, and mapped namespace handling. + /// + public interface ICsFactoryRequest + { + /// + /// Global factory management interface that provides access to Visual Studio actions, namespace management, and mapped namespaces. + /// + ICsFactoryManagement FactoryManagement { get; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSourceContainerManager.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSourceContainerManager.cs new file mode 100644 index 0000000..7e9832b --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSourceContainerManager.cs @@ -0,0 +1,41 @@ +using CodeFactory.WinVs.Models.CSharp; +using CodeFactory.WinVs.Models.CSharp.Builder; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Defines the contract for managing source containers of a specific type, providing functionality to update + /// sources, analyze code context, and manage missing using directives. + /// + /// The type of the container being managed. Must derive from . + public interface ICsSourceContainerManager : ICsSourceManager where TContainerType : CsContainer + { + /// + /// Target container being updated. + /// + TContainerType Container { get; } + + /// + /// Refreshes the current version of the update sources. + /// + /// The updated . + /// The updates hosting type. + /// Thrown if either the source or the container is null. + void UpdateSources(CsSource source, TContainerType container); + + /// + /// Analyzes the current code context and asynchronously adds any missing using directives required to resolve + /// unresolved types or namespaces. + /// + /// This method identifies missing using directives based on the current code context and + /// adds them to the appropriate location in the file. It ensures that the code compiles without unresolved + /// references. + /// A task that represents the asynchronous operation of adding missing using directives. + Task AddMissingUsingStatementsAsync(); + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSourceManager.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSourceManager.cs new file mode 100644 index 0000000..51dc65a --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSourceManager.cs @@ -0,0 +1,682 @@ +using CodeFactory.WinVs.Models.CSharp; +using CodeFactory.WinVs.Models.CSharp.Builder; +using CodeFactory.WinVs.Stats; +using System; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Defines an interface for managing and manipulating C# source code representations. + /// + /// The interface provides methods for adding, replacing, and + /// removing C# syntax elements within a source code file. It supports operations at various levels, such as + /// members, containers, and nested types, and includes transactional methods for tracking changes. + public interface ICsSourceManager : ICsFactoryManagement + { + /// + /// Gets the source code representation of the current object. + /// + CsSource Source { get; } + + /// + /// Adds the c# syntax to the source code at the specified injection location. + /// + /// Target syntax to be added. + /// The location within the source code file to inject at. + /// Thrown if either the source or the container is null after updating. + Task AddByInjectionLocationAsync(string syntax, InjectionLocation location); + + /// + /// Adds the provided syntax to the beginning of the source file. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task SourceAddToBeginningAsync(string syntax); + + + /// + /// Adds the provided syntax to the beginning of the source file. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task SourceAddToBeginningTransactionAsync(string syntax); + + /// + /// Adds the provided syntax to the end of the source file. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task SourceAddToEndAsync(string syntax); + + /// + /// Adds the provided syntax to the end of the source file. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task SourceAddToEndTransactionAsync(string syntax); + + /// + /// Adds the provided syntax before the containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task ContainerAddBeforeAsync(string syntax); + + /// + /// Adds the provided syntax before the containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task ContainerAddBeforeTransactionAsync(string syntax); + + /// + /// Adds the provided syntax after containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task ContainerAddAfterAsync(string syntax); + + /// + /// Adds the provided syntax after containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task ContainerAddAfterTransactionAsync(string syntax); + + /// + /// Adds the provided syntax to the beginning of the containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task ContainerAddToBeginningAsync(string syntax); + + /// + /// Adds the provided syntax to the beginning of the containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task ContainerAddToBeginningTransactionAsync(string syntax); + + /// + /// Adds the provided syntax to the end of the containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task ContainerAddToEndAsync(string syntax); + + /// + /// Adds the provided syntax to the end of the containers definition. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task ContainerAddToEndTransactionAsync(string syntax); + + /// + /// Adds the provided syntax before the first using statement definition. + /// + /// Target syntax to be added + /// Thrown if either the source or the container is null after updating. + Task UsingStatementsAddBeforeAsync(string syntax); + + /// + /// Adds the provided syntax before the first using statement definition. + /// + /// Target syntax to be added + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task UsingStatementsAddBeforeTransactionAsync(string syntax); + + /// + /// Adds the provided syntax before the first using statement definition. + /// + /// Target syntax to be added + /// Thrown if either the source or the container is null after updating. + Task UsingStatementsAddAfterAsync(string syntax); + + /// + /// Adds the provided syntax before the first using statement definition. + /// + /// Target syntax to be added + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task UsingStatementsAddAfterTransactionAsync(string syntax); + + /// + /// Adds the provided syntax before the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task FieldsAddBeforeAsync(string syntax); + + /// + /// Adds the provided syntax before the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task FieldsAddBeforeTransactionAsync(string syntax); + + /// + /// Adds the provided syntax after the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task FieldsAddAfterAsync(string syntax); + + /// + /// Adds the provided syntax after the field definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task FieldsAddAfterTransactionAsync(string syntax); + + /// + /// Add the provided syntax before the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task ConstructorsAddBeforeAsync(string syntax); + + /// + /// Add the provided syntax before the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task ConstructorsAddBeforeTransactionAsync(string syntax); + + /// + /// Add the provided syntax after the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task ConstructorsAddAfterAsync(string syntax); + + /// + /// Add the provided syntax after the constructor definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task ConstructorsAddAfterTransactionAsync(string syntax); + + /// + /// Add the provided syntax before the property definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task PropertiesAddBeforeAsync(string syntax); + + /// + /// Add the provided syntax before the property definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task PropertiesAddBeforeTransactionAsync(string syntax); + + /// + /// Add the provided syntax after the property definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task PropertiesAddAfterAsync(string syntax); + + /// + /// Add the provided syntax after the property definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task PropertiesAddAfterTransactionAsync(string syntax); + + /// + /// Add the provided syntax before the event definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task EventsAddBeforeAsync(string syntax); + + /// + /// Add the provided syntax before the event definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task EventsAddBeforeTransactionAsync(string syntax); + + /// + /// Add the provided syntax after the event definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task EventsAddAfterAsync(string syntax); + + /// + /// Add the provided syntax after the event definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task EventsAddAfterTransactionAsync(string syntax); + + /// + /// Add the provided syntax before the method definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task MethodsAddBeforeAsync(string syntax); + + /// + /// Add the provided syntax before the method definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task MethodsAddBeforeTransactionAsync(string syntax); + + /// + /// Add the provided syntax after the method definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task MethodsAddAfterAsync(string syntax); + + /// + /// Add the provided syntax after the method definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task MethodsAddAfterTransactionAsync(string syntax); + + + /// + /// Asynchronously adds an attribute to the specified member using the provided syntax. + /// + /// This method modifies the specified member by appending the attribute defined by the + /// provided syntax. Ensure that the syntax string is valid and conforms to the expected format for + /// attributes. + /// The member to which the attribute will be added. Cannot be null. + /// The syntax string representing the attribute to add. Cannot be null or empty. + /// A task that represents the asynchronous operation. + Task MemberAddAttributeAsync(CsMember member, string syntax); + + + /// + /// Adds an attribute to a member and returns the details of the transaction. + /// + /// The member to which the attribute will be added. Cannot be null. + /// The syntax of the attribute to be added. Must be a valid attribute syntax string. + /// A object containing information about the completed transaction. + Task MemberAddAttributeTransactionAsync(CsMember member, string syntax); + + /// + /// Asynchronously adds a specified attribute to the given container. + /// + /// The container to which the attribute will be added. Cannot be null. + /// The syntax of the attribute to add. Cannot be null or empty. + /// A task that represents the asynchronous operation. + Task ContainerAddAttributeAsync(CsContainer container, string syntax); + + /// + /// Adds an attribute to the specified container and returns the details of the transaction. + /// + /// This method performs the operation asynchronously and ensures that the attribute + /// addition then returns the details of the transaction. + /// The container to which the attribute will be added. Cannot be null. + /// The syntax defining the attribute to be added. Cannot be null or empty. + /// A object containing details of the transaction, including the status and + /// any relevant metadata. + Task ContainerAddAttributeTransactionAsync(CsContainer container, string syntax); + + /// + /// Adds a new attribute before the specified attribute model. Injecting the syntax. + /// + /// The attribute to be added. Cannot be null. + /// The syntax before which the attribute will be added. Cannot be null or empty. + /// A task that represents the asynchronous operation. + Task AttributeAddBeforeAsync(CsAttribute attribute, string syntax); + + /// + /// Adds the syntax before the attribute model. + /// + /// The attribute model the syntax is to be added before. + /// The syntax to be added before the attribute. + /// The details of what happened when the syntax was added. + Task AddBeforeTransactionAsync(CsAttribute attribute, string syntax); + + /// + /// Adds the syntax after the attribute model. + /// + /// The attribute to add the syntax after. Cannot be . + /// The syntax that will be added after the attribute model. Cannot be or empty. + /// A task that represents the asynchronous operation. + Task AttributeAddAfterAsync(CsAttribute attribute, string syntax); + + /// + /// Adds the syntax after the attribute model and returns the transaction details. + /// + /// The attribute model the syntax will be added after. Cannot be . + /// The syntax to be added after the attribute model. Cannot be . + /// A object containing the updated details of the transaction. + Task AttributeAddAfterTransactionAsync(CsAttribute attribute, string syntax); + + /// + /// Replaces the specified attribute with a new attribute defined by the provided syntax. + /// + /// The attribute to be replaced. Cannot be null. + /// The new syntax that defines the replacement attribute. Cannot be null or empty. + /// A task that represents the asynchronous operation. + Task ReplaceAttributeAsync(CsAttribute attribute, string syntax); + + /// + /// Replaces the specified attribute in a transaction and returns the updated transaction details. + /// + /// This method performs an asynchronous operation to replace an attribute in a + /// transaction. Ensure that the provided and are valid + /// and meet the requirements of the transaction system. + /// The attribute to be replaced in the transaction. Cannot be . + /// The syntax to apply to the replacement operation. Cannot be or empty. + /// A object containing the details of the updated transaction. + Task ReplaceAttributeTransactionAsync(CsAttribute attribute, string syntax); + + /// + /// Removes the specified attribute from the associated code element asynchronously. + /// + /// The attribute to remove. Must not be . + /// A task that represents the asynchronous operation. + Task RemoveAttributeAsync(CsAttribute attribute); + + /// + /// Add the syntax before the target member. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task MemberAddBeforeAsync(CsMember member, string syntax); + + /// + /// Add the syntax before the target member. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task MemberAddBeforeTransactionAsync(CsMember member, string syntax); + + /// + /// Add the syntax after the target member. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task MemberAddAfterAsync(CsMember member, string syntax); + + /// + /// Add the syntax after the target member. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task MemberAddAfterTransactionAsync(CsMember member, string syntax); + + /// + /// Comments out member from the source container. + /// + /// Target member. + /// Optional parameters sets the syntax to use when commenting out the member. This will default to use '//' + /// Thrown if either the source or the container is null after updating. + Task MemberCommentOut(CsMember member, string commentSyntax = "//"); + + /// + /// Syntax replaces the target member. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task MemberReplaceAsync(CsMember member, string syntax); + + /// + /// Syntax replaces the target member. + /// + /// Target member. + /// The syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task MemberReplaceTransactionAsync(CsMember member, string syntax); + + /// + /// Removes the target member. + /// + /// Target member. + /// Thrown if either the source or the container is null after updating. + Task MemberRemoveAsync(CsMember member); + + /// + /// Add the provided syntax before the nested enumeration definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedEnumAddBeforeAsync(string syntax); + + /// + /// Add the provided syntax before the nested enumeration definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedEnumAddBeforeTransactionAsync(string syntax); + + /// + /// Add the provided syntax after the nested enumeration definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedEnumAddAfterAsync(string syntax); + + /// + /// Add the provided syntax after the nested enumeration definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedEnumAddAfterTransactionAsync(string syntax); + + /// + /// Removes the nested enumeration. + /// + /// The target nested enumeration. + /// Thrown if either the source or the container is null after updating. + Task NestedEnumRemoveAsync(CsEnum nested); + + /// + /// Replaces the nested enumeration with the provided syntax + /// + /// The target nested enumeration. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedEnumReplaceAsync(CsEnum nested, string syntax); + + /// + /// Replaces the nested enumeration with the provided syntax + /// + /// The target nested enumeration. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedEnumReplaceTransactionAsync(CsEnum nested, string syntax); + + /// + /// Add the provided syntax before the nested interface definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedInterfaceAddBeforeAsync(string syntax); + + /// + /// Add the provided syntax before the nested interface definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedInterfaceAddBeforeTransactionAsync(string syntax); + + /// + /// Add the provided syntax after the nested interface definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedInterfaceAddAfterAsync(string syntax); + + /// + /// Add the provided syntax after the nested interface definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedInterfaceAddAfterTransactionAsync(string syntax); + + /// + /// Removes the nested interface. + /// + /// The target nested interface. + /// Thrown if either the source or the container is null after updating. + Task NestedInterfaceRemoveAsync(CsInterface nested); + + /// + /// Replaces the nested interface with the provided syntax + /// + /// The target nested interface. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedInterfaceReplaceAsync(CsInterface nested, string syntax); + + /// + /// Replaces the nested interface with the provided syntax + /// + /// The target nested interface. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedInterfaceReplaceTransactionAsync(CsInterface nested, string syntax); + + /// + /// Add the provided syntax before the nested structures definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedStructuresAddBeforeAsync(string syntax); + + /// + /// Add the provided syntax before the nested structures definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedStructuresAddBeforeTransactionAsync(string syntax); + + /// + /// Add the provided syntax after the nested structures definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedStructuresAddAfterAsync(string syntax); + + /// + /// Add the provided syntax after the nested structures definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedStructuresAddAfterTransactionAsync(string syntax); + + /// + /// Removes the nested structure. + /// + /// The target nested structure. + /// Thrown if either the source or the container is null after updating. + Task NestedStructureRemoveAsync(CsStructure nested); + + /// + /// Replaces the nested structure with the provided syntax + /// + /// The target nested structure. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedStructureReplaceAsync(CsStructure nested, string syntax); + + /// + /// Replaces the nested structure with the provided syntax + /// + /// The target nested structure. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedStructureReplaceTransactionAsync(CsStructure nested, string syntax); + + /// + /// Add the provided syntax before the nested classes definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedClassesAddBeforeAsync(string syntax); + + /// + /// Add the provided syntax before the nested classes definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedClassesAddBeforeTransactionAsync(string syntax); + + /// + /// Add the provided syntax after the nested classes definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedClassesAddAfterAsync(string syntax); + + /// + /// Add the provided syntax after the nested classes definitions. + /// + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedClassesAddAfterTransactionAsync(string syntax); + + /// + /// Removes the nested class. + /// + /// The target nested class. + /// Thrown if either the source or the container is null after updating. + Task NestedClassesRemoveAsync(CsClass nested); + + /// + /// Replaces the nested class with the provided syntax + /// + /// The target nested class. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + Task NestedClassesReplaceAsync(CsClass nested, string syntax); + + /// + /// Replaces the nested class with the provided syntax + /// + /// The target nested class. + /// Target syntax to be added. + /// Thrown if either the source or the container is null after updating. + /// The details of the updated source or null if the transaction details could not be saved. + Task NestedClassesReplaceTransactionAsync(CsClass nested, string syntax); + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSyntaxBuilder.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSyntaxBuilder.cs new file mode 100644 index 0000000..1dfbefb --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ICsSyntaxBuilder.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Defines a contract for building syntax based on a specified request. + /// + /// The type of the syntax request, which must implement . + public interface ICsSyntaxBuilder where R : ISyntaxRequest + { + /// + /// Asynchronously builds a syntax representation of the specified request. + /// + /// The request object containing the data to be processed into a syntax representation. Cannot be null. + /// A task that represents the asynchronous operation. The task result contains the syntax representation as a + /// string. + Task BuildSyntaxAsync(R request); + } + +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ISourceResult.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ISourceResult.cs new file mode 100644 index 0000000..2048c83 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ISourceResult.cs @@ -0,0 +1,46 @@ +using CodeFactory.WinVs.Models.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Contract definition for result of a CodeFactory model from a factory. + /// + public interface ISourceResult + { + /// + /// The status of the result from the factory. + /// + ResultStatusType Status { get; init; } + + /// + /// The source code model that was returned from the factory. + /// + CsSource Source { get; init; } + + /// + /// Validates the results of the factory and returns the result. + /// + /// The name of the method that called the validation. + void ValidateResult([CallerMemberName] string callerName = null); + + } + + + /// + /// Represents a source result that provides a more specific type of result. + /// + /// This interface is designed to allow for type-safe specialization of source results, enabling + /// factories or other components to return a more specific result type while maintaining compatibility with the + /// interface. + /// The specific type of source result, which must implement . + public interface ISourceResult : ISourceResult where T : ISourceResult + { + //Intetioally left blank, this is to allow for a more specific type of source result to be returned from the factory. + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ISyntaxRequest.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ISyntaxRequest.cs new file mode 100644 index 0000000..4aac226 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/ISyntaxRequest.cs @@ -0,0 +1,22 @@ +using CodeFactory.WinVs.Factory.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + + /// + /// Represents a request for syntax-related operations, providing access to factory management for Visual Studio + /// actions, namespace management, and mapped namespaces. + /// + public interface ISyntaxRequest + { + /// + /// Global factory management interface that provides access to Visual Studio actions, namespace management, and mapped namespaces. + /// + ICsFactoryManagement FactoryManagement { get; } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/SourceResultExtensions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/SourceResultExtensions.cs new file mode 100644 index 0000000..edc9797 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/CSharp/SourceResultExtensions.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory.CSharp +{ + /// + /// Extension methods class for SourceResult types. + /// + public static class SourceResultExtensions + { + /// + /// Ensures that the specified source result is valid and properly initialized for the given operation. + /// + /// This method validates the by ensuring its is not and by invoking its method. If validation fails, a is thrown with detailed context about the operation and caller. + /// The type of the source result, which must implement . + /// The source result to validate. This parameter must not be and must have a non-null + /// . + /// The name of the operation being performed. This is used to provide context in exception messages if + /// validation fails. + /// The name of the calling member. This is automatically populated by the compiler unless explicitly provided. + /// The validated source result, if it passes all validation checks. + /// Thrown if the is invalid, such as when its is . + public static T EnsureValidated(this T sourceResult, string operationName, [CallerMemberName] string callerName = null) where T : ISourceResult + { + if (sourceResult.Source == null) + throw new CodeFactoryException(ExceptionMessages.InvalidResult(operationName, callerName)); + + sourceResult.ValidateResult(callerName); + + return sourceResult; + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/ObjectNameTransformer.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/ObjectNameTransformer.cs new file mode 100644 index 0000000..f5b0dc7 --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Factory/ObjectNameTransformer.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs.Factory +{ + /// + /// Provides functionality to transform object names by removing specified prefixes and suffixes and optionally + /// adding new ones. + /// + /// The class is designed to modify object names based on + /// configurable rules. It allows removing specific prefixes and suffixes from object names and adding new ones. + /// This can be useful in scenarios where object names need to be normalized or adjusted to meet specific naming + /// conventions. Instances of this class are immutable and thread-safe. Use the static or methods to create configured instances. + public class ObjectNameTransformer + { + #region Backing fields + + /// + /// Backing field for the property + /// + private readonly ImmutableList _removePrefixes; + + /// + /// Backing field for the property + /// + private readonly ImmutableList _removeSuffixes; + + /// + /// Backing field for the property + /// + private readonly string _addPrefix; + + /// + /// Backing field for the property + /// + private readonly string _addSuffix; + + #endregion + + /// + /// Initializes a new instance of the class with specified prefixes and + /// suffixes to modify object names. + /// + /// This constructor allows customization of how object names are transformed by + /// specifying prefixes and suffixes to remove or add. The provided collections for prefixes and suffixes are + /// converted to immutable lists for thread safety. + /// A collection of prefixes to remove from object names. If null, no prefixes will be removed. + /// A collection of suffixes to remove from object names. If null, no suffixes will be removed. + /// A prefix to add to object names. Can be null or empty if no prefix should be added. + /// A suffix to add to object names. Can be null or empty if no suffix should be added. + protected ObjectNameTransformer(IEnumerable removePrefixes, IEnumerable removeSuffixes, string addPrefix, string addSuffix) + { + _removePrefixes = removePrefixes != null ? ImmutableList.Empty.AddRange(removePrefixes) : ImmutableList.Empty; + _removeSuffixes = removeSuffixes != null ? ImmutableList.Empty.AddRange(removeSuffixes) : ImmutableList.Empty; + _addPrefix = addPrefix; + _addSuffix = addSuffix; + } + + /// + /// Initializes a new instance of the class with the specified prefixes and + /// suffixes to remove or add. + /// + /// A collection of prefixes to remove from object names. Cannot be null. + /// A collection of suffixes to remove from object names. Cannot be null. + /// The prefix to add to object names. Can be null or empty if no prefix should be added. + /// The suffix to add to object names. Can be null or empty if no suffix should be added. + /// An instance of the class configured with the specified parameters. + public static ObjectNameTransformer Init(IEnumerable removePrefixes, IEnumerable removeSuffixes, string addPrefix, string addSuffix) + { + return new ObjectNameTransformer(removePrefixes, removeSuffixes, addPrefix, addSuffix); + } + + /// + /// Initializes a new instance of the class with specified prefixes and + /// suffixes to modify object names. + /// + /// A comma-separated list of prefixes to remove from object names. Can be or empty. + /// A comma-separated list of suffixes to remove from object names. Can be or empty. + /// A prefix to add to object names. Can be or empty. + /// A suffix to add to object names. Can be or empty. + /// An instance of configured with the specified prefixes and suffixes. + public static ObjectNameTransformer Init(string removePrefixes, string removeSuffixes, string addPrefix, string addSuffix) + { + return new ObjectNameTransformer(removePrefixes != null ? removePrefixes.Split(',') : null, removeSuffixes != null ? removeSuffixes.Split(',') : null, addPrefix, addSuffix); + } + + + /// + /// List of prefixes to remove from the beginning of the objects name. + /// + public IReadOnlyList RemovePrefixes => _removePrefixes; + + /// + /// List of suffixes to remove from the end of the objects name. + /// + public IReadOnlyList RemoveSuffixes => _removeSuffixes; + + /// + /// The prefix to append to the beginning of the objects name; + /// + public string AddPrefix => _addPrefix; + + /// + /// The suffix to append to the end of the objects name. + /// + public string AddSuffix => _addSuffix; + + + /// + /// Formats the specified object name by applying optional prefix and suffix modifications. + /// + /// The method performs the following transformations in order: + /// Trims leading and trailing whitespace from the input name. + /// Removes any prefixes specified in the RemovePrefixes collection if they match the + /// start of the name. Removes any suffixes specified in the + /// RemoveSuffixes collection if they match the end of the name. + /// Adds the AddPrefix value to the start of the name, if + /// specified. Adds the AddSuffix value to the end of the name, + /// if specified. If is provided, it will be + /// prepended to the final result unless it was already removed earlier. + /// The original name to format. Cannot be null or empty. + /// An optional default prefix to prepend to the formatted name. If the name already starts with this prefix, + /// it will be removed before further processing. + /// A formatted string that includes any applied prefixes or suffixes. If is + /// provided, it will be prepended to the final result. + public string FormatObjectName(string name, string defaultPrefix = null) + { + + if (string.IsNullOrEmpty(name)) return name; + + string formattedName = name.Trim(); + + if (defaultPrefix != null) + { + if (formattedName.StartsWith(defaultPrefix)) + { + formattedName = formattedName.Substring(defaultPrefix.Length); + } + } + + if (RemovePrefixes.Any()) + { + string removePrefix = RemovePrefixes.FirstOrDefault(p => formattedName.StartsWith(p)); + + if (removePrefix != null) formattedName = formattedName.Substring(removePrefix.Length); + } + + if (RemoveSuffixes.Any()) + { + string removeSuffix = RemoveSuffixes.FirstOrDefault(p => formattedName.EndsWith(p)); + + if (removeSuffix != null) formattedName = formattedName.Substring(0, formattedName.Length - (removeSuffix.Length)); + } + + if (!string.IsNullOrEmpty(AddPrefix)) formattedName = $"{AddPrefix}{formattedName}"; + + if (!string.IsNullOrEmpty(AddSuffix)) formattedName = $"{formattedName}{AddSuffix}"; + + return defaultPrefix != null + ? $"{defaultPrefix}{formattedName}" + : formattedName; + } + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/ImmutableClass.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/ImmutableClass.cs new file mode 100644 index 0000000..d37f91b --- /dev/null +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/ImmutableClass.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeFactory.WinVs +{ + /// + /// Represents an immutable container for a value of a specified reference type. + /// + /// This class ensures that the contained value cannot be set after the instance is created. + /// It is particularly useful for scenarios where immutability is required to ensure thread safety or to prevent + /// unintended modifications. The target object itself may not be thread safe. + /// The type of the value to be contained. Must be a reference type. + public class ImmutableClass where T : class + { + /// + /// Represents the underlying value of the type. + /// + /// This field is read-only and is intended to store the value associated with the + /// instance. It is not accessible outside the containing type. + private readonly T _value; + + /// + /// Initializes a new instance of the class with the specified value. + /// + /// The value to be encapsulated by the immutable class. Cannot be . + /// Thrown if is . + public ImmutableClass(T value) + { + _value = value ?? throw new ArgumentNullException(nameof(value), "Value cannot be null"); + } + + /// + /// Gets the value stored in the current instance. + /// + public T Value + { + get { return _value; } + } + + } +} diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs index ab76b29..6018f9d 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/Loader/SdkSupport.cs @@ -18,17 +18,17 @@ public static class SdkSupport /// /// The minimum version of the SDK that can be loaded and used. /// - public const string MinVersion = "2.25214.0.1"; + public const string MinVersion = "2.24224.0.1"; /// /// The maximum version of the SDK that can be loaded and used. /// - public const string MaxVersion = "2.25214.0.1"; + public const string MaxVersion = "2.25220.0.1"; /// /// The target version of the NuGet package this SDK is deployed from. /// - public const string NuGetSdkVersion = "2.25214.0.1-PreRelease"; + public const string NuGetSdkVersion = "2.25220.0.1-PreRelease"; /// /// The name of the assembly type for the CodeFactory SDK version attribute. diff --git a/Src/CodeFactoryForWindows/CodeFactory.WinVs/VsActionsExtensions.cs b/Src/CodeFactoryForWindows/CodeFactory.WinVs/VsActionsExtensions.cs index 4799c54..07049cf 100644 --- a/Src/CodeFactoryForWindows/CodeFactory.WinVs/VsActionsExtensions.cs +++ b/Src/CodeFactoryForWindows/CodeFactory.WinVs/VsActionsExtensions.cs @@ -173,5 +173,83 @@ public static async Task GetCSharpSourceAsync(this IVsActions source, return await source.GetCSharpSourceAsync(member.ModelSourceFile); } + + /// + /// Asynchronously loads an external configuration command based on the specified command type and Visual Studio + /// model. + /// + /// This method attempts to load the external configuration command by first determining + /// the appropriate folder path based on the and the value of . If a folder path is determined, the configuration is loaded by folder. + /// Otherwise, it falls back to loading the configuration by project. + /// The instance used to perform Visual Studio-related actions. Cannot be null. + /// The type of the command to load. This is typically a string identifier for the command. + /// The instance representing the context for the command. Cannot be null. + /// A boolean value indicating whether to load the configuration based on the folder structure. If , the configuration is loaded by folder; otherwise, it is loaded by project. + /// A task that represents the asynchronous operation. The task result contains the loaded instance, or if the operation fails or the inputs are + /// invalid. + public static async Task LoadExternalConfigAsync(this IVsActions source, string commandType, VsModel commandResult, bool loadFolderConfiguration = true) + { + if (source == null) return null; + if (commandResult == null) return null; + + //Holds the name of the project folder. + string folderPath = null; + + //Holds the result of the command configuration that is loaded. + ConfigCommand result = null; + + //Getting the folder path is only required if we are loading the configuration by folder structure. + if (loadFolderConfiguration) + { + switch (commandResult.ModelType) + { + case VisualStudioModelType.CSharpSource: + + + var csSource = commandResult as VsCSharpSource; + + if (csSource != null) + { + var csSourceFolder = await csSource.GetParentProjectFolderAsync(); + folderPath = csSourceFolder?.Path; + } + + break; + + case VisualStudioModelType.ProjectFolder: + + //If the command result is a project folder then we can use the path directly. + folderPath = ((VsProjectFolder)commandResult).Path; + break; + + case VisualStudioModelType.Document: + + var docSource = commandResult as VsDocument; + + if (docSource != null) + { + var csSourceFolder = await docSource.GetParentProjectFolderAsync(); + folderPath = csSourceFolder?.Path; + } + break; + + default: + //setting the folder path to null will cause the command to load by project. + folderPath = null; + break; + } + + + if (folderPath != null) result = await ExternalConfig.LoadCommandByFolderAsync(commandType, folderPath, commandResult); + } + + result ??= await ExternalConfig.LoadCommandByProjectAsync(commandType, commandResult); + + return result; + + } } } diff --git a/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj b/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj index aa0c3a5..ed48617 100644 --- a/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj +++ b/Src/CodeFactoryForWindows/CodeFactory/CodeFactory.csproj @@ -6,7 +6,7 @@ True CFSigner.snk True - 2.25214.0.1-PreRelease + 2.25220.0.1-PreRelease CodeFactory, LLC. CodeFactory, LLC. CodeFactory Base Library @@ -17,11 +17,11 @@ False CodeFactory Base Libraries 2.0.0.0 - 2.25214.0.1 + 2.25220.0.1 CFLogo128.png git - Release Updates for 2.25214.0.1 + Release Updates for 2.25220.0.1 Recompile Release: When you update your automation to this version of the SDK. diff --git a/Src/CodeFactoryForWindows/CodeFactory/SourceFormatter.cs b/Src/CodeFactoryForWindows/CodeFactory/SourceFormatter.cs index 534b935..2720e18 100644 --- a/Src/CodeFactoryForWindows/CodeFactory/SourceFormatter.cs +++ b/Src/CodeFactoryForWindows/CodeFactory/SourceFormatter.cs @@ -1,6 +1,6 @@ //***************************************************************************** //* Code Factory SDK -//* Copyright (c) 2023 CodeFactory, LLC +//* Copyright (c) 2023-2025 CodeFactory, LLC //***************************************************************************** using System; using System.Collections.Generic; @@ -42,6 +42,50 @@ public void AppendCode(string code) _codeFormatter.Append(code); } + /// + /// Appends the specified code to the internal formatter, preceded by the specified level of indentation. + /// + /// Each indentation level corresponds to a predefined indentation statement. If + /// is or empty, the method performs no action. + /// The number of indentation levels to prepend before appending the code. Must be non-negative. + /// The code to append. Cannot be or empty. + public void AppendCode(int indentLevel, string code) + { + if (string.IsNullOrEmpty(code)) return; + + // Append the indent level + for (int i = 0; i < indentLevel; i++) + { + _codeFormatter.Append(_indentStatement); + } + // Append the code + _codeFormatter.Append(code); + } + + /// + /// Appends the specified code to the internal formatter, preceded by the specified indentation level, and adds + /// a new line at the end. + /// + /// This method formats the code by adding the specified number of indentation levels + /// before appending it, followed by a new line. If is null or empty, the method + /// performs no action. + /// The number of indentation levels to prepend before the code. Must be non-negative. + /// The code to append. Cannot be null or empty. + public void AppendCodeEndWithNewLine(int indentLevel, string code) + { + if (string.IsNullOrEmpty(code)) return; + + // Append the indent level + for (int i = 0; i < indentLevel; i++) + { + _codeFormatter.Append(_indentStatement); + } + // Append the code + _codeFormatter.Append(code); + + _codeFormatter.AppendLine(); + } + /// /// Appends a new line of code to the formatter. ///