diff --git a/src/LibraryManager/Json/LibraryStateToFileConverter.cs b/src/LibraryManager/Json/LibraryStateToFileConverter.cs
index ef77e5807..4c75f9738 100644
--- a/src/LibraryManager/Json/LibraryStateToFileConverter.cs
+++ b/src/LibraryManager/Json/LibraryStateToFileConverter.cs
@@ -1,4 +1,9 @@
-using Microsoft.Web.LibraryManager.Contracts;
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
+using Microsoft.Web.LibraryManager.Contracts;
using Microsoft.Web.LibraryManager.LibraryNaming;
namespace Microsoft.Web.LibraryManager.Json
@@ -22,10 +27,14 @@ public ILibraryInstallationState ConvertToLibraryInstallationState(LibraryInstal
}
string provider = string.IsNullOrEmpty(stateOnDisk.ProviderId) ? _defaultProvider : stateOnDisk.ProviderId;
- string destination = string.IsNullOrEmpty(stateOnDisk.DestinationPath) ? _defaultDestination : stateOnDisk.DestinationPath;
+
+ (string name, string version) = LibraryIdToNameAndVersionConverter.Instance.GetLibraryNameAndVersion(stateOnDisk.LibraryId, provider);
+ string destination = string.IsNullOrEmpty(stateOnDisk.DestinationPath) ? ExpandDestination(_defaultDestination, name, version) : stateOnDisk.DestinationPath;
var state = new LibraryInstallationState()
{
+ Name = name,
+ Version = version,
IsUsingDefaultDestination = string.IsNullOrEmpty(stateOnDisk.DestinationPath),
IsUsingDefaultProvider = string.IsNullOrEmpty(stateOnDisk.ProviderId),
ProviderId = provider,
@@ -33,11 +42,34 @@ public ILibraryInstallationState ConvertToLibraryInstallationState(LibraryInstal
Files = stateOnDisk.Files
};
- (state.Name, state.Version) = LibraryIdToNameAndVersionConverter.Instance.GetLibraryNameAndVersion(stateOnDisk.LibraryId, provider);
-
return state;
}
+ ///
+ /// Expands [Name] and [Version] tokens in the DefaultDestination
+ ///
+ /// The default destination string
+ /// Package name
+ /// Package version
+ ///
+ [SuppressMessage("Globalization", "CA1307:Specify StringComparison for clarity", Justification = "Not available on net481, not needed here (caseless)")]
+ private string ExpandDestination(string destination, string name, string version)
+ {
+ if (!destination.Contains("["))
+ {
+ return destination;
+ }
+
+ // if the name contains a slash (either filesystem or scoped packages),
+ // trim that and only take the last segment.
+ int cutIndex = name.LastIndexOfAny(['/', '\\']);
+
+ StringBuilder stringBuilder = new StringBuilder(destination);
+ stringBuilder.Replace("[Name]", cutIndex == -1 ? name : name.Substring(cutIndex + 1));
+ stringBuilder.Replace("[Version]", version);
+ return stringBuilder.ToString();
+ }
+
public LibraryInstallationStateOnDisk ConvertToLibraryInstallationStateOnDisk(ILibraryInstallationState state)
{
if (state == null)
diff --git a/test/LibraryManager.Test/Json/LibraryStateToFileConverterTests.cs b/test/LibraryManager.Test/Json/LibraryStateToFileConverterTests.cs
new file mode 100644
index 000000000..41b6c3387
--- /dev/null
+++ b/test/LibraryManager.Test/Json/LibraryStateToFileConverterTests.cs
@@ -0,0 +1,109 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.Web.LibraryManager.Contracts;
+using Microsoft.Web.LibraryManager.Json;
+using Microsoft.Web.LibraryManager.LibraryNaming;
+using Microsoft.Web.LibraryManager.Mocks;
+using Microsoft.Web.LibraryManager.Providers.Cdnjs;
+
+namespace Microsoft.Web.LibraryManager.Test.Json
+{
+ [TestClass]
+ public class LibraryStateToFileConverterTests
+ {
+ [TestInitialize]
+ public void Setup()
+ {
+ string cacheFolder = Environment.ExpandEnvironmentVariables(@"%localappdata%\Microsoft\Library\");
+ string projectFolder = Path.Combine(Path.GetTempPath(), "LibraryManager");
+ var hostInteraction = new HostInteraction(projectFolder, cacheFolder);
+ var dependencies = new Dependencies(hostInteraction, new CdnjsProviderFactory());
+ IProvider provider = dependencies.GetProvider("cdnjs");
+ LibraryIdToNameAndVersionConverter.Instance.Reinitialize(dependencies);
+ }
+
+ [TestMethod]
+ public void ConvertToLibraryInstallationState_NullStateOnDisk()
+ {
+ LibraryStateToFileConverter converter = new LibraryStateToFileConverter("provider", "destination");
+
+ ILibraryInstallationState result = converter.ConvertToLibraryInstallationState(null);
+
+ Assert.IsNull(result);
+ }
+
+ [TestMethod]
+ public void ConvertToLibraryInstallationState_UseDefaultProviderAndDestination()
+ {
+ LibraryStateToFileConverter converter = new LibraryStateToFileConverter("defaultProvider", "defaultDestination");
+
+ var stateOnDisk = new LibraryInstallationStateOnDisk
+ {
+ LibraryId = "libraryId",
+ };
+
+ ILibraryInstallationState result = converter.ConvertToLibraryInstallationState(stateOnDisk);
+
+ Assert.AreEqual("defaultProvider", result.ProviderId);
+ Assert.AreEqual("defaultDestination", result.DestinationPath);
+ }
+
+ [TestMethod]
+ public void ConvertToLibraryInstallationState_OverrideProviderAndDestination()
+ {
+ LibraryStateToFileConverter converter = new LibraryStateToFileConverter("defaultProvider", "defaultDestination");
+
+ var stateOnDisk = new LibraryInstallationStateOnDisk
+ {
+ LibraryId = "libraryId",
+ ProviderId = "provider",
+ DestinationPath = "destination",
+ };
+
+ ILibraryInstallationState result = converter.ConvertToLibraryInstallationState(stateOnDisk);
+
+ Assert.AreEqual("provider", result.ProviderId);
+ Assert.AreEqual("destination", result.DestinationPath);
+ }
+
+ [TestMethod]
+ public void ConvertToLibraryInstallationState_ExpandTokensInDefaultDestination()
+ {
+ LibraryStateToFileConverter converter = new LibraryStateToFileConverter("defaultProvider", "lib/[Name]/[Version]");
+
+ var stateOnDisk = new LibraryInstallationStateOnDisk
+ {
+ LibraryId = "testLibraryId@1.0",
+ // it needs to be a provider that uses the versioned naming scheme
+ ProviderId = "cdnjs",
+ };
+
+ ILibraryInstallationState result = converter.ConvertToLibraryInstallationState(stateOnDisk);
+
+ Assert.AreEqual("lib/testLibraryId/1.0", result.DestinationPath);
+ }
+
+ [TestMethod]
+ [DataRow("filesystem", "c:\\path\\to\\library")]
+ [DataRow("filesystem", "/path/to/library")]
+ [DataRow("cdnjs", "@scope/library@1.0.0")]
+ public void ConvertToLibraryInstallationState_ExpandTokensInDefaultDestination_NamesWithSlashes(string provider, string libraryId)
+ {
+ LibraryStateToFileConverter converter = new LibraryStateToFileConverter("defaultProvider", "lib/[Name]");
+
+ var stateOnDisk = new LibraryInstallationStateOnDisk
+ {
+ LibraryId = libraryId,
+ ProviderId = provider,
+ };
+
+ ILibraryInstallationState result = converter.ConvertToLibraryInstallationState(stateOnDisk);
+
+ Assert.AreEqual("lib/library", result.DestinationPath);
+ }
+ }
+}