diff --git a/PowerForge.Tests/ModuleInformationReaderTests.cs b/PowerForge.Tests/ModuleInformationReaderTests.cs
new file mode 100644
index 00000000..5774fc5c
--- /dev/null
+++ b/PowerForge.Tests/ModuleInformationReaderTests.cs
@@ -0,0 +1,59 @@
+using System.IO;
+
+namespace PowerForge.Tests;
+
+public sealed class ModuleInformationReaderTests
+{
+ [Fact]
+ public void Read_PrefersPrereleaseFromPsData()
+ {
+ var projectRoot = CreateModuleProject(
+ """
+ @{
+ RootModule = 'Sample.psm1'
+ ModuleVersion = '1.2.3'
+ PrivateData = @{
+ PSData = @{
+ Prerelease = 'preview1'
+ }
+ }
+ }
+ """);
+
+ var reader = new ModuleInformationReader();
+
+ var result = reader.Read(projectRoot);
+
+ Assert.Equal("preview1", result.PreRelease);
+ }
+
+ [Fact]
+ public void Read_FallsBackToTopLevelPrerelease()
+ {
+ var projectRoot = CreateModuleProject(
+ """
+ @{
+ RootModule = 'Sample.psm1'
+ ModuleVersion = '1.2.3'
+ Prerelease = 'beta2'
+ }
+ """);
+
+ var reader = new ModuleInformationReader();
+
+ var result = reader.Read(projectRoot);
+
+ Assert.Equal("beta2", result.PreRelease);
+ }
+
+ private static string CreateModuleProject(string manifestContent)
+ {
+ var projectRoot = Path.Combine(Path.GetTempPath(), "PowerForgeModuleInformationTests", Path.GetRandomFileName());
+ Directory.CreateDirectory(projectRoot);
+
+ File.WriteAllText(Path.Combine(projectRoot, "Sample.psd1"), manifestContent);
+ File.WriteAllText(Path.Combine(projectRoot, "Sample.psm1"), string.Empty);
+
+ return projectRoot;
+ }
+}
diff --git a/PowerForge/Models/ModuleInformation.cs b/PowerForge/Models/ModuleInformation.cs
index 9a9265c0..df203596 100644
--- a/PowerForge/Models/ModuleInformation.cs
+++ b/PowerForge/Models/ModuleInformation.cs
@@ -19,6 +19,8 @@ public sealed class ModuleInformation
public string? RootModule { get; }
/// PowerShell version requirement from the manifest (PowerShellVersion).
public string? PowerShellVersion { get; }
+ /// Prerelease label from the manifest when present.
+ public string? PreRelease { get; }
/// GUID value from the manifest (GUID), when present and parseable.
public Guid? Guid { get; }
/// Typed RequiredModules entries extracted from the manifest.
@@ -36,6 +38,7 @@ public ModuleInformation(
string? moduleVersion,
string? rootModule,
string? powerShellVersion,
+ string? preRelease,
Guid? guid,
RequiredModuleReference[] requiredModules,
string? manifestText)
@@ -46,6 +49,7 @@ public ModuleInformation(
ModuleVersion = moduleVersion;
RootModule = rootModule;
PowerShellVersion = powerShellVersion;
+ PreRelease = preRelease;
Guid = guid;
RequiredModules = requiredModules ?? Array.Empty();
ManifestText = manifestText;
diff --git a/PowerForge/Services/ModuleInformationReader.cs b/PowerForge/Services/ModuleInformationReader.cs
index 62736717..8c7aae63 100644
--- a/PowerForge/Services/ModuleInformationReader.cs
+++ b/PowerForge/Services/ModuleInformationReader.cs
@@ -40,6 +40,7 @@ public ModuleInformation Read(string projectPath)
string? moduleVersion = null;
string? rootModule = null;
string? powerShellVersion = null;
+ string? preRelease = null;
Guid? guid = null;
RequiredModuleReference[] requiredModules = Array.Empty();
string? manifestText = null;
@@ -52,6 +53,15 @@ public ModuleInformation Read(string projectPath)
rootModule = rm;
if (ManifestEditor.TryGetTopLevelString(manifestPath, "PowerShellVersion", out var psv))
powerShellVersion = psv;
+ if (ManifestEditor.TryGetPsDataStringArray(manifestPath, "Prerelease", out var prereleaseValues) &&
+ prereleaseValues is { Length: > 0 })
+ {
+ preRelease = prereleaseValues[0];
+ }
+ else if (ManifestEditor.TryGetTopLevelString(manifestPath, "Prerelease", out var topLevelPrerelease))
+ {
+ preRelease = topLevelPrerelease;
+ }
if (ManifestEditor.TryGetTopLevelString(manifestPath, "GUID", out var guidString))
{
if (System.Guid.TryParse(guidString, out var g))
@@ -82,6 +92,7 @@ public ModuleInformation Read(string projectPath)
moduleVersion: moduleVersion,
rootModule: rootModule,
powerShellVersion: powerShellVersion,
+ preRelease: preRelease,
guid: guid,
requiredModules: requiredModules,
manifestText: manifestText);