From a00e3b341bbddc559a5af618e4a6e520b7bbb2d6 Mon Sep 17 00:00:00 2001 From: "Denis Kuzmin (github/3F)" Date: Mon, 29 Apr 2024 23:41:39 +0300 Subject: [PATCH] MvsSln 2.7. Public release. * NEW: Added default skeleton for SlnWriter in an attempt to make it easier to create from scratch. Empty .Write() methods will use it by default or merge it with the actual Map. * NEW: Added asynchronous metods* for SlnWriter *Both implementations including legacy netfx4.0 target platform, and async/await for modern. * NEW: Added SMap implementation to wrap ISlnResult.Map. More control over ISection and its handler. * NEW: Added LhDataHelper as an additional way to prepare default handlers from data (ISlnWhData). ``` LhDataHelper hdata = new(); hdata.SetHeader(SlnHeader.MakeDefault()) .SetProjects(projects) .SetProjectConfigs(prjConfs) .SetSolutionConfigs(slnConf); using SlnWriter w = new(solutionFile, hdata); ``` See related issue #61 for details. * NEW: Implemented CreateProjectsIfNotExist option for SlnWriter. ``` using SlnWriter w = new(solutionFile, hdata); w.Options = SlnWriterOptions.CreateProjectsIfNotExist; // it will write according ProjectType information (both legacy or sdk-style) w.Write(); ``` Use +IProjectsToucher to override implementation. You can find complete example in #61 * NEW: New modern LineBuilder to make creating new handlers easier or control EOL. Related issue #57. * NEW: Added DefaultHandlers wrapper to prepare all default according to ISlnResult(ISlnWhData). * NEW: SlnWriter: + WriteAsString() & WriteAsStringAsync() to save the result as string instead of file. ``` using SlnWriter w = new(handlers); string data = await w.WriteAsStringAsync(sln.Result.Map); ``` * NEW: Added platform independent IObjHandler.NewLine to specify the EOL for used w\handlers. +.UpdateNewLine() extension for a collection of handlers. * NEW: New modern IXProject.AddReference(.., AddReferenceOptions) to control everything for `Reference` nodes. Old signatures has been marked as obsolete and scheduled to be removed in future versions. ``` Default = HideEmbedInteropTypes | HideSpecificVersion, DefaultResolve = Default | ResolveAssemblyName | OmitArchitecture | OmitCultureNeutral | ... Mini = Default | HidePrivate, MiniResolve = Mini | DefaultResolve | OmitCulture, ``` See related issue #61 for details. * NEW: SlnWriter now supports ISlnResult -> +ISlnWhData data to preapre default handlers itself. * NEW: Implemented overriding of GetHashCode/Equals for ImportElement, RoProperties, Projects.Item. * NEW: +IConfPlatform.IsEqualPair(IConfPlatform) * NEW: ProjectItem adds ability to generate a project name from a specified input path: slnDir\ProjectName\src.csproj -> ProjectName slnDir\ProjectName.csproj -> ProjectName ``` new ProjectItem(ProjectType.CsSdk, @$"{projName}\src.csproj", slnDir: baseDir) ``` * FIXED: Fixed bug with a disappearing `EndProject`. See related #56 * FIXED: Fixed duplicated lines when disabling some features through SlnItems. * FIXED: Fixed lines being ignored when handlers are not prepared. * FIXED: If the handler is not initialized as object, the corresponding entry is lost. * FIXED: Fixed PackageInfo == Equals for null. * CHANGED: SlnParser has been switched to UTF8 by default. * CHANGED: SlnWriter now will ignore W\handler that will return null value at IObjHandler.Extract(). * CHANGED: Removed comparing of parent project and origin item in PropertyItem.Equals. * CHANGED: SlnHeader is sealed now with new ctors and added SlnHeader.MakeDefault(). * CHANGED: ConfigPrj: new ctors +protected internal set for IncludeInBuild and IncludeInDeploy properties. * CHANGED: Projects.Item and PropertyItem: new ctors & renamed evaluatedValue, evaluatedInclude, unevaluatedValue, unevaluatedInclude Old access still is available but marked as obsolete and scheduled to be removed in future versions. * CHANGED: Updated path \ / logic between Windows and unix-like systems. --- .version | 2 +- MvsSln/MvsSln.csproj | 8 +- MvsSln/MvsSlnVersion.cs | 2 +- Readme.md | 180 +++++++++++++++++++++++----------------- changelog.txt | 124 +++++++++++++++++++++++---- 5 files changed, 218 insertions(+), 98 deletions(-) diff --git a/.version b/.version index d5724cd..9aa3464 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.6.2 \ No newline at end of file +2.7.0 \ No newline at end of file diff --git a/MvsSln/MvsSln.csproj b/MvsSln/MvsSln.csproj index 3f384ff..9c81956 100644 --- a/MvsSln/MvsSln.csproj +++ b/MvsSln/MvsSln.csproj @@ -3,7 +3,7 @@ - 2.6.2 + 2.7.0 @@ -18,7 +18,7 @@ [ MvsSln ] Customizable VisualStudio .sln parser, projects, r/w handlers at runtime MvsSln_v1_96px.png https://raw.githubusercontent.com/3F/MvsSln/master/MvsSln/Resources/MvsSln_v1_96px.png - Customizable VisualStudio .sln parser, Complex support of the projects (.vcxproj, .csproj., …), Pluginable lightweight r/w handlers at runtime, and more … + Customizable VisualStudio .sln parser with project support (.vcxproj, .csproj., …). Pluggable lightweight r/w handlers at runtime, and more … 🌌 The most convenient work with projects, dependencies, their lazy loading, any folders, any items, references and much more in these different worlds; @@ -34,8 +34,8 @@ 🎈 Source code and details: https://github.com/3F/MvsSln - ======================================= - gnt /p:ngpackages="MvsSln/$(Version)" + ====================== + gnt MvsSln/$(Version) ================== https://github.com/3F/GetNuTool $(BuildInfoVSSBE) diff --git a/MvsSln/MvsSlnVersion.cs b/MvsSln/MvsSlnVersion.cs index dcb1737..03fabdc 100644 --- a/MvsSln/MvsSlnVersion.cs +++ b/MvsSln/MvsSlnVersion.cs @@ -8,7 +8,7 @@ namespace net.r_eg.MvsSln { public static readonly Version number = new Version(S_NUM_REV); - public const string S_NUM = "2.6.2"; + public const string S_NUM = "2.7.0"; public const string S_REV = "0"; public const string S_NUM_REV = S_NUM + "." + S_REV; diff --git a/Readme.md b/Readme.md index 95016b4..d5202a2 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ [![](https://raw.githubusercontent.com/3F/MvsSln/master/MvsSln/Resources/MvsSln_v1_96px.png)](https://github.com/3F/MvsSln) [**MvsSln**](https://github.com/3F/MvsSln) -Customizable VisualStudio .sln parser, Complex support of the projects (.vcxproj, .csproj., …), Pluginable lightweight r/w handlers at runtime, and more … 🧩 +Customizable VisualStudio .sln parser with project support (.vcxproj, .csproj., …). Pluggable lightweight r/w handlers at runtime, and more … 🧩 ```r Copyright (c) 2013-2024 Denis Kuzmin github/3F @@ -10,7 +10,7 @@ Copyright (c) 2013-2024 Denis Kuzmin github/3F MvsSln contributors https://github.com/3F/MvsSln/graphs/contributors -We're waiting for your awesome contributions! +[*MvsSln*](https://github.com/3F/MvsSln) is waiting for your awesome contributions!
@@ -25,7 +25,7 @@ We're waiting for your awesome contributions!
-## Why MvsSln ? +## Why MvsSln MvsSln provides the easiest way to complex work with Visual Studio .sln files and referenced projects (.vcxproj, .csproj., ...). Merge, Manage, Attach custom handlers and more. Because it's free, because it's open. @@ -44,9 +44,9 @@ Safely compare anything, ```csharp if(new ProjectItem(...) == new ProjectItem(...)) { ... } if(new SolutionFolder(...) == new SolutionFolder(...)) { ... } -if(new RawText(...) == new RawText(...)) { ... } if(new ConfigItem(...) == new ConfigItem(...)) { ... } if(new PackageInfo(...) == new PackageInfo(...)) { ... } +... ```` @@ -131,6 +131,34 @@ IPackageInfo found = l.Result.PackagesConfigs Version v = l.Result.PackagesConfigs.First().GetPackage("LX4Cnh")?.VersionParsed; ``` +Easily create files [from scratch](https://github.com/3F/MvsSln/issues/61#issuecomment-2079155362), + +```csharp +// 2.7+ +LhDataHelper hdata = new(); +hdata.SetHeader(SlnHeader.MakeDefault()) + .SetProjects(projects) + .SetProjectConfigs(prjConfs) + .SetSolutionConfigs(slnConf); + +using(SlnWriter w = new(solutionFile, hdata)) +{ + w.Options = SlnWriterOptions.CreateProjectsIfNotExist; + w.Write(); +} + +using Sln sln = new(solutionFile, SlnItems.EnvWithMinimalProjects); +IXProject xp = sln.Result.Env.Projects.First(); + +xp.SetProperties(new Dictionary() +{ + { "OutputType", "EXE" }, + { "TargetFramework", "net8.0" }, + { "Platforms", "x64" } +}); +xp.Save(); +``` + Everything at hand, ```csharp @@ -272,98 +300,66 @@ using(var w = new SlnWriter(".sln", whandlers)) { } ``` -## Did you know - -### Projects - -The 1 project instance means only the 1 project with specific configuration. That is, you should work with each instance separately if some project has 2 or more configurations: +## Projects. Adding References -``` -First instance of project {4F8BB8CD-1116-4F07-9B8F-06D69FB8589B} with configuration 'Release_net45|Any CPU' that's related with solution cfg -> CI_Release_net45|Any CPU -Second instance of project {4F8BB8CD-1116-4F07-9B8F-06D69FB8589B} with configuration 'Debug|Any CPU' that's related with solution cfg -> Debug|Any CPU -... +```csharp +XProject.AddPackageReference("Conari", "1.5.0"); ``` -For example, the [vsSolutionBuildEvent](https://github.com/3F/vsSolutionBuildEvent) contains 10 projects and 8 solution configurations: - -``` -DBG_SDK10; DBG_SDK15; DCI_SDK10; DCI_SDK15; REL_SDK10; REL_SDK15; RCI_SDK10; RCI_SDK15 +```csharp +xp.AddProjectReference(projects.First()); +xp.AddProjectReference(new ProjectItem(ProjectType.Cs, @$"{projName}\src.csproj")); ``` -Maximum **possible** configurations for each projects above should be calculated as 10 * 8 = 80, ie. 80 instances that *can be* loaded as each different project. `EnvWithProjects` will try load all available, but in fact, mostly 2 or more project-configuration can be related to the same 1 solution-configuration, therefore it can be just 30 or even 20 in reality, and so on. - -However, if you need to work only with common data of specified project: -* Just use any available configuration. That is, to load projects only with specific configuration, use for example `IEnvironment.LoadProjects`. - ```csharp -// SlnItems.Env will initialize environment without loading projects. -using(var sln = new Sln(@"vsSolutionBuildEvent.sln", SlnItems.Env)) -{ - ISlnResult data = sln.Result; - IConfPlatform slnCfg = data.SolutionConfigs.FirstOrDefault(); // to get first available solution configuration - data.Env.LoadProjects( - // prepare final list of projects that should be loaded - data.ProjectItemsConfigs.Where(p => p.solutionConfig == slnCfg) - ); - //... data.Env.Projects will contain instances only for Where(p => p.solutionConfig == slnCfg) i.e. 8 in total -} +xp.AddReference(Assembly.GetExecutingAssembly()); ``` -**For modern versions** also available `IEnvironment.LoadMinimalProjects` or `EnvWithMinimalProjects` flag. - -### Adding Reference & Assembly name - ```csharp -XProject.AddReference(lib, false); +XProject.AddReference("DllExport", lib, AddReferenceOptions.MakeRelativePath); ``` -```xml - - ..\packages\DllExport.1.6.4\gcache\metalib\DllExport.dll - False - +```csharp +xp.AddReference( + pathToDll, + AddReferenceOptions.DefaultResolve | AddReferenceOptions.OmitVersion | AddReferenceOptions.HidePrivate +); ``` -```csharp -XProject.AddReference("DllExport", lib, false); +```xml + ``` ```xml - + ..\packages\DllExport.1.6.4\gcache\metalib\DllExport.dll False ``` -You can also specify it via `System.Reflection.Assembly` etc. - ## Example of extending (your custom handlers) Example of `LProject` handler (**reader**): ```csharp +using static net.r_eg.MvsSln.Core.Keywords; + public class LProject: LAbstract, ISlnHandler { + public override ICollection CoHandlers { get; protected set; } + = [typeof(LProjectDependencies)]; + public override bool IsActivated(ISvc svc) - { - return ((svc.Sln.ResultType & SlnItems.Projects) == SlnItems.Projects); - } + => (svc.Sln.ResultType & SlnItems.Projects) == SlnItems.Projects; public override bool Condition(RawText line) - { - return line.trimmed.StartsWith("Project(", StringComparison.Ordinal); - } + => line.trimmed.StartsWith(Project_, StringComparison.Ordinal); public override bool Positioned(ISvc svc, RawText line) { - var pItem = GetProjectItem(line.trimmed, svc.Sln.SolutionDir); - if(pItem.pGuid == null) { - return false; - } - - if(svc.Sln.ProjectItemList == null) { - svc.Sln.ProjectItemList = new List(); - } + ProjectItem pItem = GetProjectItem(line.trimmed, svc.Sln.SolutionDir); + if(pItem.pGuid == null) return false; + if(svc.Sln.ProjectItemList == null) svc.Sln.ProjectItemList = []; svc.Sln.ProjectItemList.Add(pItem); return true; @@ -374,31 +370,59 @@ public class LProject: LAbstract, ISlnHandler Example of `WSolutionConfigurationPlatforms` handler (**writer**): ```csharp -public class WSolutionConfigurationPlatforms: WAbstract, IObjHandler +using static net.r_eg.MvsSln.Core.Keywords; + +public class WSolutionConfigurationPlatforms(IEnumerable configs) + : WAbstract, IObjHandler { - protected IEnumerable configs; + protected IEnumerable configs = configs; public override string Extract(object data) { - LineBuilder lb = new(); - - lb.AppendLv1Line("GlobalSection(SolutionConfigurationPlatforms) = preSolution"); + if(configs == null) return null; - configs.ForEach(cfg => lb.AppendLv2Line($"{cfg} = {cfg}")); + lbuilder.Clear(); + lbuilder.AppendLv1Line(SolutionConfigurationPlatformsPreSolution); - return lb.AppendLv1("EndGlobalSection").ToString(); - } + configs.ForEach(cfg => lbuilder.AppendLv2Line($"{cfg} = {cfg}")); - public WSolutionConfigurationPlatforms(IEnumerable configs) - { - this.configs = configs ?? throw new ArgumentNullException(nameof(configs)); + return lbuilder.AppendLv1(EndGlobalSection).ToString(); } } ``` -## How to get MvsSln +## Download MvsSln + +NuGet | [GetNuTool](https://github.com/3F/GetNuTool) +------|--------------------------------------------- +[![package](https://img.shields.io/nuget/v/MvsSln.svg)](https://www.nuget.org/packages/MvsSln/) | [`gnt MvsSln`](https://3F.github.io/GetNuTool/releases/latest/gnt/) + +## Build MvsSln from source + +```bat +git clone https://github.com/3F/MvsSln.git MvsSln +cd MvsSln +``` + +### Windows. Visual Studio / MSBuild + +```bat +build Release +``` +or together with configured [netfx4sdk](https://github.com/3F/netfx4sdk) -* NuGet: [![NuGet package](https://img.shields.io/nuget/v/MvsSln.svg)](https://www.nuget.org/packages/MvsSln/) -* [GetNuTool](https://github.com/3F/GetNuTool): `msbuild gnt.core /p:ngpackages="MvsSln"` or **[gnt](https://3f.github.io/GetNuTool/releases/latest/gnt/)** /p:ngpackages="MvsSln" -* [GitHub Releases](https://github.com/3F/MvsSln/releases) [ [latest](https://github.com/3F/MvsSln/releases/latest) ] -* CI builds: [`CI /artifacts`](https://ci.appveyor.com/project/3Fs/mvssln-fxjnf/history) ( [old CI](https://ci.appveyor.com/project/3Fs/mvssln/history) ) or find `🎲 CI build` on [GitHub Releases](https://github.com/3F/MvsSln/releases) page. +```bat +build-CI Release +``` + +### Ubuntu 20.04 + +```sh +dotnet build -c Release +``` + +### run unit tests + +```sh +dotnet test -c Release --no-build --no-restore +``` diff --git a/changelog.txt b/changelog.txt index 47208e7..71636f0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,13 +2,109 @@ MvsSln - https://github.com/3F/MvsSln - - - - - - - - - - - - - - - - - - - -[v2.6.2] 2023.07.12 +[2.7] 2024.04.29 + + * NEW: Added default skeleton for SlnWriter in an attempt to make it easier to create from scratch. + Empty .Write() methods will use it by default or merge it with the actual Map. + + * NEW: Added asynchronous metods* for SlnWriter + *Both implementations including legacy netfx4.0 target platform, and async/await for modern. + + * NEW: Added SMap implementation to wrap ISlnResult.Map. More control over ISection and its handler. + + * NEW: Added LhDataHelper as an additional way to prepare default handlers from data (ISlnWhData). + ``` + LhDataHelper hdata = new(); + hdata.SetHeader(SlnHeader.MakeDefault()) + .SetProjects(projects) + .SetProjectConfigs(prjConfs) + .SetSolutionConfigs(slnConf); + + using SlnWriter w = new(solutionFile, hdata); + ``` + See related issue #61 for details. + + * NEW: Implemented CreateProjectsIfNotExist option for SlnWriter. + ``` + using SlnWriter w = new(solutionFile, hdata); + w.Options = SlnWriterOptions.CreateProjectsIfNotExist; + // it will write according ProjectType information (both legacy or sdk-style) + w.Write(); + ``` + Use +IProjectsToucher to override implementation. + You can find complete example in #61 + + * NEW: New modern LineBuilder to make creating new handlers easier or control EOL. Related issue #57. + + * NEW: Added DefaultHandlers wrapper to prepare all default according to ISlnResult(ISlnWhData). + + * NEW: SlnWriter: + WriteAsString() & WriteAsStringAsync() to save the result as string instead of file. + ``` + using SlnWriter w = new(handlers); + string data = await w.WriteAsStringAsync(sln.Result.Map); + ``` + + * NEW: Added platform independent IObjHandler.NewLine to specify the EOL for used w\handlers. + +.UpdateNewLine() extension for a collection of handlers. + + * NEW: New modern IXProject.AddReference(.., AddReferenceOptions) to control everything for `Reference` nodes. + Old signatures has been marked as obsolete and scheduled to be removed in future versions. + ``` + Default = HideEmbedInteropTypes | HideSpecificVersion, + DefaultResolve = Default | ResolveAssemblyName | OmitArchitecture | OmitCultureNeutral | ... + Mini = Default | HidePrivate, + MiniResolve = Mini | DefaultResolve | OmitCulture, + ``` + See related issue #61 for details. + + * NEW: SlnWriter now supports ISlnResult -> +ISlnWhData data to preapre default handlers itself. + + * NEW: Implemented overriding of GetHashCode/Equals for ImportElement, RoProperties, Projects.Item. + + * NEW: +IConfPlatform.IsEqualPair(IConfPlatform) + + * NEW: ProjectItem adds ability to generate a project name from a specified input path: + slnDir\ProjectName\src.csproj -> ProjectName + slnDir\ProjectName.csproj -> ProjectName + ``` + new ProjectItem(ProjectType.CsSdk, @$"{projName}\src.csproj", slnDir: baseDir) + ``` + + * FIXED: Fixed bug with a disappearing `EndProject`. See related #56 + + * FIXED: Fixed duplicated lines when disabling some features through SlnItems. + + * FIXED: Fixed lines being ignored when handlers are not prepared. + + * FIXED: If the handler is not initialized as object, the corresponding entry is lost. + + * FIXED: Fixed PackageInfo == Equals for null. + + * CHANGED: SlnParser has been switched to UTF8 by default. + + * CHANGED: SlnWriter now will ignore W\handler that will return null value at IObjHandler.Extract(). + + * CHANGED: Removed comparing of parent project and origin item in PropertyItem.Equals. + + * CHANGED: SlnHeader is sealed now with new ctors and added SlnHeader.MakeDefault(). + + * CHANGED: ConfigPrj: new ctors +protected internal set for IncludeInBuild and IncludeInDeploy properties. + + * CHANGED: Projects.Item and PropertyItem: + new ctors & renamed evaluatedValue, evaluatedInclude, unevaluatedValue, unevaluatedInclude + Old access still is available but marked as obsolete and scheduled to be removed in future versions. + + * CHANGED: Updated path \ / logic between Windows and unix-like systems. + + +[2.6.2] 2023.07.12 * FIXED: Fix issue with string builder removing too much raw sln data on Unix platforms. Related issue: https://github.com/3F/MvsSln/issues/57 Related PR: https://github.com/3F/MvsSln/pull/58 -[v2.6.1] 2022.02.01 + +[2.6.1] 2022.02.01 * FIXED: Incorrect project instances for the active solution configuration in XProject Environment. Related issue: https://github.com/3F/vsSolutionBuildEvent/issues/71 @@ -22,7 +118,7 @@ MvsSln - https://github.com/3F/MvsSln Otherwise, same logic from v2.5.3 described here: https://github.com/3F/MvsSln/blob/0ec96021b7/MvsSln/Extensions/ProjectItemExtension.cs#L59-L77 -[v2.6] 2021.08.23 +[2.6] 2021.08.23 * FIXED: Fixed CalculateHashCode() Extension. Internally affects many objects due to broken GetHashCode(). @@ -58,7 +154,7 @@ MvsSln - https://github.com/3F/MvsSln Use `ToString()` and `IConfPlatform.Formatted` instead. -[v2.5.3] 2020.07.23 +[2.5.3] 2020.07.23 * FIXED: Fixed XProjectEnv. Issue #29 XProjectByFile() can destroy original properties that was prepared for solution. @@ -78,7 +174,7 @@ MvsSln - https://github.com/3F/MvsSln https://github.com/dotnet/project-system/blob/master/docs/opening-with-new-project-system.md -[v2.5.2] 2020.05.05 +[2.5.2] 2020.05.05 * NEW: Activating ProjectReferences for existing ProjectDependencies (shallow copy) through new flag. Issue #25. @@ -116,7 +212,7 @@ MvsSln - https://github.com/3F/MvsSln * CHANGED: Updated Microsoft.Build 16.5.0 (Only for: netcoreapp2.1) -[v2.5.1] 2020.01.30 +[2.5.1] 2020.01.30 * FIXED: Fixed NullReferenceException when empty xml nodes in PropertyItem through ProjectProperty. This is possible for global or environment properties, for example: @@ -147,7 +243,7 @@ MvsSln - https://github.com/3F/MvsSln https://twitter.com/GitHub3F/status/1219348325729816578 -[v2.5] 2019.10.17 +[2.5] 2019.10.17 * FIXED: Fixed parallelism problems when using Sln wrapper. @@ -184,7 +280,7 @@ MvsSln - https://github.com/3F/MvsSln https://github.com/3F/MvsSln/milestone/4 -[v2.4] 2019.08.10 +[2.4] 2019.08.10 * FIXED: "The format ... of configuration is not supported". Issue #19. @@ -281,7 +377,7 @@ MvsSln - https://github.com/3F/MvsSln Find any relevant use of the new features in that project. -[v2.3] 2019.06.17 +[2.3] 2019.06.17 * FIXED: Added support of `.` character in solution/project configuration name. Issue #13. @@ -311,7 +407,7 @@ MvsSln - https://github.com/3F/MvsSln Release notes: https://github.com/3F/hMSBuild/releases/tag/v2.1 -[v2.2] 2019.04.08 +[2.2] 2019.04.08 * FIXED: Fixed possible error when loading all found projects: 'An equivalent project is already present in the project collection, ...' @@ -366,7 +462,7 @@ MvsSln - https://github.com/3F/MvsSln * https://github.com/3F/hMSBuild/releases/tag/v2.0 -[v2.1] 2018.08.05 +[2.1] 2018.08.05 * FIXED: Fixed bug 'The node is not parented by this object' When IXProject.RemoveImport is used for `Import` elements inside `ImportGroup`. @@ -387,7 +483,7 @@ MvsSln - https://github.com/3F/MvsSln * +`XProject(string file, IDictionary properties)` * +`XProject(Project prj)` -[v2.0] 2017.10.05 +[2.0] 2017.10.05 * NEW: Updated architecture now provides 2 types of handlers - readers (ISlnHandler) and writers (IObjHandler). You also can use your custom reader or writer, just implement an `ISlnHandler` or `IObjHandler`: @@ -458,7 +554,7 @@ MvsSln - https://github.com/3F/MvsSln * KNOWN_PROBLEM: C++ projects and their initialization for Visual Studio 2017. Issue #1. -[v1.0.1] 2017.07.21 +[1.0.1] 2017.07.21 * FIXED: Fixed possible bug with already loaded project in collection when initializing new instance of Sln. * FIXED: Fixed `IXProject.RemoveProperty(PropertyItem property)` & `IXProject.RemoveItem(Item item)` when selected items or properties does not exist. @@ -502,7 +598,7 @@ MvsSln - https://github.com/3F/MvsSln It has been wrapped by `ImportElement` to avoid using MBE. -[v1.0] 2017.07.07 +[1.0] 2017.07.07 * Initial public release. Extracted from vsSolutionBuildEvent project: https://github.com/3F/vsSolutionBuildEvent