Ionite
9 months ago
3 changed files with 122 additions and 2 deletions
@ -0,0 +1,105 @@
|
||||
using System.Diagnostics.CodeAnalysis; |
||||
using System.Text.RegularExpressions; |
||||
using JetBrains.Annotations; |
||||
using Semver; |
||||
using StabilityMatrix.Core.Processes; |
||||
|
||||
namespace StabilityMatrix.Core.Models.Packages.Extensions; |
||||
|
||||
/// <summary> |
||||
/// Extension specifier with optional version constraints. |
||||
/// </summary> |
||||
[PublicAPI] |
||||
public partial class ExtensionSpecifier |
||||
{ |
||||
public required string Name { get; init; } |
||||
|
||||
public string? Constraint { get; init; } |
||||
|
||||
public string? Version { get; init; } |
||||
|
||||
public string? VersionConstraint => Constraint is null || Version is null ? null : Constraint + Version; |
||||
|
||||
public bool TryGetSemVersionRange([NotNullWhen(true)] out SemVersionRange? semVersionRange) |
||||
{ |
||||
if (!string.IsNullOrEmpty(VersionConstraint)) |
||||
{ |
||||
return SemVersionRange.TryParse( |
||||
VersionConstraint, |
||||
SemVersionRangeOptions.Loose, |
||||
out semVersionRange |
||||
); |
||||
} |
||||
|
||||
semVersionRange = null; |
||||
return false; |
||||
} |
||||
|
||||
public static ExtensionSpecifier Parse(string value) |
||||
{ |
||||
TryParse(value, true, out var packageSpecifier); |
||||
|
||||
return packageSpecifier!; |
||||
} |
||||
|
||||
public static bool TryParse(string value, [NotNullWhen(true)] out ExtensionSpecifier? extensionSpecifier) |
||||
{ |
||||
return TryParse(value, false, out extensionSpecifier); |
||||
} |
||||
|
||||
private static bool TryParse( |
||||
string value, |
||||
bool throwOnFailure, |
||||
[NotNullWhen(true)] out ExtensionSpecifier? packageSpecifier |
||||
) |
||||
{ |
||||
var match = ExtensionSpecifierRegex().Match(value); |
||||
if (!match.Success) |
||||
{ |
||||
if (throwOnFailure) |
||||
{ |
||||
throw new ArgumentException($"Invalid extension specifier: {value}"); |
||||
} |
||||
|
||||
packageSpecifier = null; |
||||
return false; |
||||
} |
||||
|
||||
packageSpecifier = new ExtensionSpecifier |
||||
{ |
||||
Name = match.Groups["extension_name"].Value, |
||||
Constraint = match.Groups["version_constraint"].Value, |
||||
Version = match.Groups["version"].Value |
||||
}; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/// <inheritdoc /> |
||||
public override string ToString() |
||||
{ |
||||
return Name + VersionConstraint; |
||||
} |
||||
|
||||
public static implicit operator Argument(ExtensionSpecifier specifier) |
||||
{ |
||||
return specifier.VersionConstraint is null |
||||
? new Argument(specifier.Name) |
||||
: new Argument((specifier.Name, specifier.VersionConstraint)); |
||||
} |
||||
|
||||
public static implicit operator ExtensionSpecifier(string specifier) |
||||
{ |
||||
return Parse(specifier); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Regex to match a pip package specifier. |
||||
/// </summary> |
||||
[GeneratedRegex( |
||||
@"(?<extension_name>\S+)\s*(?<version_constraint>==|>=|<=|>|<|~=|!=)?\s*(?<version>[a-zA-Z0-9_.]+)?", |
||||
RegexOptions.CultureInvariant, |
||||
5000 |
||||
)] |
||||
private static partial Regex ExtensionSpecifierRegex(); |
||||
} |
Loading…
Reference in new issue