diff --git a/src/Tools/Convert2SDKProject/Newtonsoft.Json.dll b/src/Tools/Convert2SDKProject/Newtonsoft.Json.dll new file mode 100644 index 0000000000..01c89478b2 Binary files /dev/null and b/src/Tools/Convert2SDKProject/Newtonsoft.Json.dll differ diff --git a/src/Tools/Convert2SDKProject/XSConvert2SDK.prgx b/src/Tools/Convert2SDKProject/XSConvert2SDK.prgx new file mode 100644 index 0000000000..dbd4904572 --- /dev/null +++ b/src/Tools/Convert2SDKProject/XSConvert2SDK.prgx @@ -0,0 +1,285 @@ +#r "System.Xml.XDocument.dll" +//#r "System.Text.Json.dll" +#r "Newtonsoft.Json.dll" + +USING System +USING System.Collections.Generic +USING System.Linq +USING System.Text +USING System.Xml +USING System.Xml.Linq +USING System.IO +//using System.Text.Json +using Newtonsoft.Json + +// What is the Project to convert ? +VAR xsProjFile := "" +IF Args:Count >= 1 + xsProjFile := Args[0] +ENDIF +IF String.IsNullOrEmpty( xsProjFile ) + InfoMessage( "Usage : XSConvert2SDK " ) + InfoMessage( " is the 'classic' XSharp Project File.") + RETURN +ENDIF + +InfoMessage( "Running XSConvert2SDK ..." ) +InfoMessage( "Project : " + xsProjFile ) + +TRY + VAR converter := ProjectConversion{} + converter:DoConvert( xsProjFile ) +CATCH ex AS Exception + ErrorMessage( "An error occurred during conversion: " + Environment.NewLine + ex:Message ) +END TRY + + + +CLASS ProjectConversion + PRIVATE nugetPackages AS List + PRIVATE externalDlls AS List + + PRIVATE moveToNuget AS Dictionary> + PRIVATE propertiesToKeep AS List + + PRIVATE orgFileName AS STRING + + CONSTRUCTOR() + // Move External DLLs => Nuget Packages + LoadNugetMapping() + // Keep Compiler Switches + LoadPropertiesToKeep() + END CONSTRUCTOR + + METHOD DoConvert( prjFile AS STRING ) AS VOID + IF !File.Exists(prjFile) + ErrorMessage( "Please provide the path to the .xsproj file as an argument." ) + RETURN + ENDIF + // + orgFileName := prjFile + // + LOCAL doc AS XDocument + doc := XDocument.Load(orgFileName) + // + VAR ns := doc:Root:Name:Namespace + VAR propertyGroup := doc:Root:Element(ns + "PropertyGroup") + // --- Read Properties --- + VAR properties := propertyGroup? ; + :Elements() ;// tous les sous-éléments + :ToDictionary( ; + { el => el:Name:LocalName }, ; // name + { el => el:Value } ; // value + ); + // + + VAR assemblyName := propertyGroup?; + :Element(ns + "AssemblyName")?; + :Value + + // --- Read references --- + VAR references := doc:Root; + :Elements(ns + "ItemGroup"); + :Elements(ns + "Reference"); + :ToList() + + // Process references to determine which are NuGet packages and which are external DLLs + SELF:nugetPackages := List{} + SELF:externalDlls := List{} + FOREACH VAR reference IN references + VAR include := reference:Attribute("Include")?:Value + VAR hintPath := reference:Element(ns + "HintPath")?:Value + // Skip system assemblies + IF (hintPath != NULL) + // Case 1: NuGet package + IF (hintPath:Contains("packages")) + // Example: ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + VAR folder := hintPath:Split('\\'); + :FirstOrDefault( { p => p:Contains(".") } ) + + IF (folder != NULL) + VAR parts := folder:Split('.') + IF (parts:Length >= 4) + VAR Name := "" + VAR Version := "" + + // Build the name (all parts except the last 3) + FOR VAR i := 0 TO parts:Length - 3 + IF (i > 0) + Name += "." + ENDIF + Name += parts[i] + NEXT + + // Build the version (last 3 parts) + FOR VAR i := parts:Length - 3 TO parts:Length + IF (i > parts:Length - 3) + Version += "." + ENDIF + Version += parts[i] + NEXT + // + nugetPackages:Add(TUPLE(Name, Version)) + ENDIF + ENDIF + ELSE + // Case 2: External DLL + CheckExternalDLL( hintPath, TRUE ) + ENDIF + ELSE + // No HintPath, treat as external reference (could be GAC or project reference, but we'll keep it simple) + // So, don't add it to externalDlls, but check if it should be replaced by a NuGet package + CheckExternalDLL( include, FALSE ) + ENDIF + NEXT + + // Process properties to keep only those we want + properties := FilterAndProcessProperties( properties ) + + + // --- Build new SDK-style project --- + VAR newProject := XElement{"Project"} + newProject:SetAttributeValue("Sdk", "Microsoft.NET.Sdk") + + // --- Add back properties we want to keep --- + VAR newPropertyGroup := XElement{"PropertyGroup"} + IF (properties:Any()) + FOREACH VAR prop IN properties + newPropertyGroup:Add( XElement{prop:Key, prop:Value} ) + NEXT + ENDIF + IF (!String.IsNullOrEmpty(assemblyName)) + newPropertyGroup:Add( XElement{"AssemblyName", assemblyName}) + ENDIF + newProject:Add(newPropertyGroup) + + // --- Add PackageReference entries --- + IF (nugetPackages:Any()) + VAR packageGroup := XElement{"ItemGroup"} + FOREACH VAR pkg IN nugetPackages + packageGroup:Add(; + XElement{"PackageReference",; + XAttribute{"Include", pkg:Name},; + XAttribute{"Version", pkg:Version}}; + ) + NEXT + newProject:Add(packageGroup) + ENDIF + + // --- Add external DLL references --- + IF (externalDlls:Any()) + VAR dllGroup := XElement{"ItemGroup"} + FOREACH VAR dll IN externalDlls + dllGroup:Add(; + XElement{"Reference",; + XAttribute{"Include", Path.GetFileNameWithoutExtension(dll)},; + XElement{"HintPath", dll}}; + ) + NEXT + newProject:Add(dllGroup) + ENDIF + + // + VAR backup := prjFile + ".bak" + IF (File.Exists(backup)) + File.Delete(backup) + ENDIF + File.Move(prjFile, backup) + + // --- Save result --- + VAR newDoc := XDocument{newProject} + newDoc:Save(prjFile) + + InfoMessage("Project file updated successfully. Original backed up as: " + backup) + + END METHOD + + PRIVATE METHOD CheckExternalDLL( hintPath AS STRING, AddExternal AS LOGIC ) AS VOID + hintPath := hintPath:ToLower() + IF !hintPath:EndsWith(".dll") + hintPath := hintPath + ".dll" + ENDIF + VAR external := Path.GetFileNameWithoutExtension( hintPath ) + FOREACH VAR mapping IN moveToNuget + IF mapping:Value:Exists( { x => x:ToLower() == external }) + // This DLL should be replaced by a NuGet package, so skip it + IF !nugetPackages:Exists( { p => p:Name:ToLower() == mapping:Key:ToLower() } ) + nugetPackages:Add(TUPLE(mapping:Key, "*")) + ENDIF + RETURN + ENDIF + NEXT + IF AddExternal + externalDlls:Add( hintPath ) + ENDIF + END METHOD + + PRIVATE METHOD LoadNugetMapping() AS VOID + VAR jsonFile := "moveToNuget.json" + IF (File.Exists(jsonFile)) + VAR jsonString := File.ReadAllText(jsonFile) + //SELF:moveToNuget := JsonSerializer.Deserialize>>(jsonString) // .NET Core version + SELF:moveToNuget := JsonConvert.DeserializeObject>>(jsonString) // Newtonsoft Version + ELSE + moveToNuget := Dictionary>{} + moveToNuget:Add( "XSharp.Core", List{ { "XSharp.Core" } }) + moveToNuget:Add( "XSharp.RT", List{ { "XSharp.Data", "XSharp.MacroCompiler", "XSharp.RDD", "XSharp.RT.Debugger", "XSharp.RT"} } ) + moveToNuget:Add( "XSharp.Harbour", List{ {"XSharp.Harbour" } } ) + moveToNuget:Add( "XSharp.VFP", List{ {"XSharp.VFP" } } ) + moveToNuget:Add( "XSharp.VO", List{ {"XSharp.VO" } } ) + moveToNuget:Add( "XSharp.VOSDK", List{ {"VOConsoleClasses", "VOGUIClasses", "VOInternetClasses", "VORDDClasses", "VOReportClasses", "VOSQLClasses", "VOSystemClasses", "VOWin32APILibrary" } } ) + moveToNuget:Add( "XSharp.VOSDKTyped", List{ {"VOConsoleClasses", "VOGUIClasses", "VORDDClasses", "VOSQLClasses", "VOSystemClasses"} } ) + moveToNuget:Add( "XSharp.XPP", List{ {"XSharp.XPP" } } ) + ENDIF + END METHOD + + PRIVATE METHOD LoadPropertiesToKeep() AS VOID + VAR jsonFile := "propertiesToKeep.json" + IF (File.Exists(jsonFile)) + VAR jsonString := File.ReadAllText(jsonFile) + // SELF:propertiesToKeep := JsonSerializer.Deserialize>(jsonString) // .NET Core version + SELF:propertiesToKeep := JsonConvert.DeserializeObject>(jsonString) // Newtonsoft Version + ELSE + propertiesToKeep := List{} + propertiesToKeep:AddRange( {"Allowdot","InitLocals","INS","LB","Memvar","NS","OutputType","OVF","Undeclared","UnSafe","VO10","VO11","VO12","Vo15", ; + "VO2", "VO3","VO4","VO5","VO6","VO7","VO8","VO9","TargetFrameworkVersion"} ) + ENDIF + END METHOD + + + PRIVATE METHOD FilterAndProcessProperties( properties AS Dictionary ) AS Dictionary + VAR result := Dictionary{} + FOREACH VAR prop IN properties + IF propertiesToKeep:Contains( prop:Key ) + // Convert TargetFrameworkVersion format + IF prop:Key == "TargetFrameworkVersion" + VAR pValue := prop:Value + IF pValue:StartsWith("v") + pValue := "net" + pValue:Substring(1):Replace(".", "") + ENDIF + result:Add(prop:Key, pValue) + ELSE + result:Add(prop:Key, prop:Value) + ENDIF + ENDIF + NEXT + RETURN result + END METHOD + +END CLASS + +FUNCTION ErrorMessage( msg AS STRING ) AS VOID + VAR clr := Console.ForegroundColor + Console.ForegroundColor := ConsoleColor.Red + Console.WriteLine( msg ) + Console.ForegroundColor := clr + RETURN + +FUNCTION InfoMessage( msg AS STRING ) AS VOID + VAR clr := Console.ForegroundColor + Console.ForegroundColor := ConsoleColor.White + Console.WriteLine( msg ) + Console.ForegroundColor := clr + RETURN + + // FUNCTION CheckProperties( xx AS xx ) AS xx diff --git a/src/Tools/Convert2SDKProject/moveToNuget.json b/src/Tools/Convert2SDKProject/moveToNuget.json new file mode 100644 index 0000000000..1af69e3995 --- /dev/null +++ b/src/Tools/Convert2SDKProject/moveToNuget.json @@ -0,0 +1,41 @@ +{ + "XSharp.Core": [ + "XSharp.Core" + ], + "XSharp.RT": [ + "XSharp.Data", + "XSharp.MacroCompiler", + "XSharp.RDD", + "XSharp.RT.Debugger", + "XSharp.RT" + ], + "XSharp.Harbour": [ + "XSharp.Harbour" + ], + "XSharp.VFP": [ + "XSharp.VFP" + ], + "XSharp.VO": [ + "XSharp.VO" + ], + "XSharp.VOSDK": [ + "VOConsoleClasses", + "VOGUIClasses", + "VOInternetClasses", + "VORDDClasses", + "VOReportClasses", + "VOSQLClasses", + "VOSystemClasses", + "VOWin32APILibrary" + ], + "XSharp.VOSDKTyped": [ + "VOConsoleClasses", + "VOGUIClasses", + "VORDDClasses", + "VOSQLClasses", + "VOSystemClasses" + ], + "XSharp.XPP": [ + "XSharp.XPP" + ] +} \ No newline at end of file diff --git a/src/Tools/Convert2SDKProject/propertiesToKeep.json b/src/Tools/Convert2SDKProject/propertiesToKeep.json new file mode 100644 index 0000000000..cdb950e1f4 --- /dev/null +++ b/src/Tools/Convert2SDKProject/propertiesToKeep.json @@ -0,0 +1,49 @@ +[ + "Allowdot", + "ApplicationIcon", + "AssemblyName", + "AZ", + "Comments", + "Configuration", + "CS", + "Dialect", + "FOVF", + "GenerateFullPaths", + "IncludePaths", + "InitLocals", + "INS", + "LB", + "Memvar", + "Name", + "NamedArgs", + "Nologo", + "NoStandardDefs", + "NoWin32Manifest", + "NS", + "OutputType", + "OVF", + "PlatformTarget", + "RootNamespace", + "StandardDefs", + "StartupObject", + "TargetFrameworkProfile", + "TargetFrameworkVersion", + "TransporterVersion", + "Undeclared", + "UnSafe", + "VO1", + "VO10", + "VO11", + "VO12", + "VO15", + "VO16", + "VO2", + "VO3", + "VO4", + "VO5", + "VO6", + "VO7", + "VO8", + "VO9", + "VulcanCompatibleResources" +] \ No newline at end of file