diff --git a/src/Dotnet.Script.DependencyModel.Nuget/Dotnet.Script.DependencyModel.NuGet.csproj b/src/Dotnet.Script.DependencyModel.Nuget/Dotnet.Script.DependencyModel.NuGet.csproj index 89ab6d87..fb37205a 100644 --- a/src/Dotnet.Script.DependencyModel.Nuget/Dotnet.Script.DependencyModel.NuGet.csproj +++ b/src/Dotnet.Script.DependencyModel.Nuget/Dotnet.Script.DependencyModel.NuGet.csproj @@ -12,7 +12,12 @@ A MetadataReferenceResolver that allows inline nuget references to be specified in script(csx) files. dotnet-script dotnet-script + latest + + + + diff --git a/src/Dotnet.Script.DependencyModel.Nuget/NuGetSourceReferenceResolver.cs b/src/Dotnet.Script.DependencyModel.Nuget/NuGetSourceReferenceResolver.cs index 46ceb5d0..89075cfb 100644 --- a/src/Dotnet.Script.DependencyModel.Nuget/NuGetSourceReferenceResolver.cs +++ b/src/Dotnet.Script.DependencyModel.Nuget/NuGetSourceReferenceResolver.cs @@ -1,9 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; -using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; +using Dotnet.Script.DependencyModel.ProjectSystem; namespace Dotnet.Script.DependencyModel.NuGet { @@ -15,7 +14,6 @@ public class NuGetSourceReferenceResolver : SourceReferenceResolver { private readonly SourceReferenceResolver _sourceReferenceResolver; private readonly IDictionary> _scriptMap; - private static readonly Regex PackageNameMatcher = new Regex(@"\s*nuget\s*:\s*(.*)\s*,", RegexOptions.Compiled | RegexOptions.IgnoreCase); public NuGetSourceReferenceResolver(SourceReferenceResolver sourceReferenceResolver, IDictionary> scriptMap) { @@ -48,9 +46,8 @@ public override string NormalizePath(string path, string baseFilePath) public override string ResolveReference(string path, string baseFilePath) { - if (path.StartsWith("nuget:", StringComparison.OrdinalIgnoreCase)) + if (ScriptParser.TryParseNuGetPackageReference(path, out var packageName, out _)) { - var packageName = PackageNameMatcher.Match(path).Groups[1].Value; if (_scriptMap.TryGetValue(packageName, out var scripts)) { if (scripts.Count == 1) @@ -66,9 +63,8 @@ public override string ResolveReference(string path, string baseFilePath) public override Stream OpenRead(string resolvedPath) { - if (resolvedPath.StartsWith("nuget:", StringComparison.OrdinalIgnoreCase)) + if (ScriptParser.TryParseNuGetPackageReference(resolvedPath, out var packageName, out _)) { - var packageName = PackageNameMatcher.Match(resolvedPath).Groups[1].Value; var scripts = _scriptMap[packageName]; if (scripts.Count == 1) { diff --git a/src/Dotnet.Script.DependencyModel/Dotnet.Script.DependencyModel.csproj b/src/Dotnet.Script.DependencyModel/Dotnet.Script.DependencyModel.csproj index 4c72e346..eb07e720 100644 --- a/src/Dotnet.Script.DependencyModel/Dotnet.Script.DependencyModel.csproj +++ b/src/Dotnet.Script.DependencyModel/Dotnet.Script.DependencyModel.csproj @@ -19,6 +19,12 @@ + + + ScriptParser.cs + + + diff --git a/src/Dotnet.Script.DependencyModel/ProjectSystem/PackageVersion.cs b/src/Dotnet.Script.DependencyModel/ProjectSystem/PackageVersion.cs index 27a65249..8f484b0b 100644 --- a/src/Dotnet.Script.DependencyModel/ProjectSystem/PackageVersion.cs +++ b/src/Dotnet.Script.DependencyModel/ProjectSystem/PackageVersion.cs @@ -8,7 +8,38 @@ namespace Dotnet.Script.DependencyModel.ProjectSystem /// public class PackageVersion : IEquatable { - private static readonly Regex IsPinnedRegex = new Regex(@"^(?>\[\d+[^,\]]+(? ::= "0" + // | + // | + // + // ::= + // | + // + // ::= "0" + // | + // + // ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" + + const string NumericPattern = @"(?:0|[1-9][0-9]*)"; + + // ::= + // | "-" + // | "+" + // | "-" "+" + // + // ::= "." "." + + const string MajorPlusVersionPattern = NumericPattern + @"(?:\." + NumericPattern + @")"; + const string VersionSuffixPattern = @"(?:[+-][\w][\w+.-]*)?"; + + private static readonly Regex IsPinnedRegex = + new Regex(@"^(?>\[" + MajorPlusVersionPattern + @"{1,4}" + VersionSuffixPattern + @"\]" + + @"|" + MajorPlusVersionPattern + @"{2,3}" + VersionSuffixPattern + @")$", + RegexOptions.Compiled); /// /// Initializes a new instance of the class. diff --git a/src/Dotnet.Script.DependencyModel/ProjectSystem/ScriptParser.cs b/src/Dotnet.Script.DependencyModel/ProjectSystem/ScriptParser.cs index 0d5c1439..b6a8e4b5 100644 --- a/src/Dotnet.Script.DependencyModel/ProjectSystem/ScriptParser.cs +++ b/src/Dotnet.Script.DependencyModel/ProjectSystem/ScriptParser.cs @@ -6,7 +6,7 @@ namespace Dotnet.Script.DependencyModel.ProjectSystem { - public class ScriptParser + public partial class ScriptParser { private readonly Logger _logger; @@ -37,15 +37,6 @@ public ParseResult ParseFromFiles(IEnumerable csxFiles) return new ParseResult(allPackageReferences); } - const string Hws = @"[\x20\t]*"; // hws = horizontal whitespace - - const string DirectivePatternPrefix = @"^" - + Hws + @"#"; - const string DirectivePatternSuffix = Hws + @"""nuget:" - // https://github.com/NuGet/docs.microsoft.com-nuget/issues/543#issue-270039223 - + Hws + @"(\w+(?:[_.-]\w+)*)" - + @"(?:" + Hws + "," + Hws + @"(.+?))?"""; - private static IEnumerable ReadPackageReferencesFromReferenceDirective(string fileContent) { const string pattern = DirectivePatternPrefix + "r" + DirectivePatternSuffix; diff --git a/src/Dotnet.Script.DependencyModel/ProjectSystem/ScriptParserInternal.cs b/src/Dotnet.Script.DependencyModel/ProjectSystem/ScriptParserInternal.cs new file mode 100644 index 00000000..c931b700 --- /dev/null +++ b/src/Dotnet.Script.DependencyModel/ProjectSystem/ScriptParserInternal.cs @@ -0,0 +1,31 @@ +using System.Text.RegularExpressions; + +namespace Dotnet.Script.DependencyModel.ProjectSystem +{ + partial class ScriptParser + { + const string Hws = @"[\x20\t]*"; // hws = horizontal whitespace + + const string NuGetPattern = @"nuget:" + // https://github.com/NuGet/docs.microsoft.com-nuget/issues/543#issue-270039223 + + Hws + @"(\w+(?:[_.-]\w+)*)" + + @"(?:" + Hws + "," + Hws + @"(.+?))?"; + + const string WholeNuGetPattern = @"^" + NuGetPattern + @"$"; + + const string DirectivePatternPrefix = @"^" + Hws + @"#"; + const string DirectivePatternSuffix = Hws + @"""" + NuGetPattern + @""""; + + internal static bool TryParseNuGetPackageReference(string input, + out string id, out string version) + { + bool success; + (success, id, version) = + Regex.Match(input, WholeNuGetPattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase) + is {} match && match.Success + ? (true, match.Groups[1].Value, match.Groups[2].Value) + : default; + return success; + } + } +} diff --git a/src/Dotnet.Script.Tests/PackageVersionTests.cs b/src/Dotnet.Script.Tests/PackageVersionTests.cs index ac632c7b..2f8b64a6 100644 --- a/src/Dotnet.Script.Tests/PackageVersionTests.cs +++ b/src/Dotnet.Script.Tests/PackageVersionTests.cs @@ -12,6 +12,10 @@ public class PackageVersionTests [Theory] [InlineData("1.2.3")] [InlineData("1.2.3.4")] + [InlineData("1.2.3-beta1")] + [InlineData("0.1.4-beta")] // See: https://github.com/filipw/dotnet-script/issues/407#issuecomment-563363947 + [InlineData("2.0.0-preview3.20122.2")] // See: https://github.com/filipw/dotnet-script/issues/407#issuecomment-631122591 + [InlineData("1.0.0-ci-20180920T1656")] [InlineData("[1.2]")] [InlineData("[1.2.3]")] [InlineData("[1.2.3-beta1]")]