Skip to content

Commit efe6a57

Browse files
committed
Add ConvertFrom(Regex) support
1 parent 7990878 commit efe6a57

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

dotnet/src/webdriver/BiDi/Modules/Script/LocalValue.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
using System.Linq;
2424
using System.Numerics;
2525
using System.Text.Json.Serialization;
26+
using System.Text.RegularExpressions;
2627

2728
namespace OpenQA.Selenium.BiDi.Modules.Script;
2829

@@ -79,6 +80,9 @@ public static LocalValue ConvertFrom(object? value)
7980
case string str:
8081
return ConvertFrom(str);
8182

83+
case Regex regex:
84+
return ConvertFrom(regex);
85+
8286
case { } when value.GetType().GetInterfaces()
8387
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ISet<>)):
8488
{
@@ -155,6 +159,27 @@ public static LocalValue ConvertFrom(string? value)
155159
return new NullLocalValue();
156160
}
157161

162+
/// <summary>
163+
/// Converts a .NET Regex into a BiDi Regex
164+
/// </summary>
165+
/// <param name="regex">A .NET Regex.</param>
166+
/// <returns>A BiDi Regex.</returns>
167+
/// <remarks>
168+
/// Note that the .NET regular expression engine does not work the same as the JavaScript engine.
169+
/// To minimize the differences between the two engines, it is recommended to enabled the <see cref="RegexOptions.ECMAScript"/> option.
170+
/// </remarks>
171+
public static LocalValue ConvertFrom(Regex? regex)
172+
{
173+
if (regex is null)
174+
{
175+
return new NullLocalValue();
176+
}
177+
178+
string? flags = RegExpValue.GetRegExpFlags(regex.Options);
179+
180+
return new RegExpLocalValue(new RegExpValue(regex.ToString()) { Flags = flags });
181+
}
182+
158183
public static LocalValue ConvertFrom(DateTime? value)
159184
{
160185
if (value is null)

dotnet/src/webdriver/BiDi/Modules/Script/RegExpValue.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,62 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using System;
21+
using System.Diagnostics;
22+
using System.Text.RegularExpressions;
23+
2024
namespace OpenQA.Selenium.BiDi.Modules.Script;
2125

2226
public record RegExpValue(string Pattern)
2327
{
2428
public string? Flags { get; set; }
29+
30+
internal static string? GetRegExpFlags(RegexOptions options)
31+
{
32+
if (options == RegexOptions.None)
33+
{
34+
return null;
35+
}
36+
37+
string flags = string.Empty;
38+
const RegexOptions NonBacktracking = (RegexOptions)1024;
39+
#if NET8_0_OR_GREATER
40+
Debug.Assert(NonBacktracking == RegexOptions.NonBacktracking);
41+
#endif
42+
const RegexOptions NonApplicableOptions = RegexOptions.Compiled | NonBacktracking;
43+
44+
const RegexOptions UnsupportedOptions =
45+
RegexOptions.ExplicitCapture |
46+
RegexOptions.IgnorePatternWhitespace |
47+
RegexOptions.RightToLeft |
48+
RegexOptions.CultureInvariant;
49+
50+
options &= ~NonApplicableOptions;
51+
if ((options & UnsupportedOptions) != 0)
52+
{
53+
throw new NotSupportedException($"The selected RegEx options are not supported in BiDi: {options & UnsupportedOptions}");
54+
}
55+
56+
if ((options & RegexOptions.IgnoreCase) != 0)
57+
{
58+
flags += "i";
59+
options = options & ~RegexOptions.IgnoreCase;
60+
}
61+
62+
if ((options & RegexOptions.Multiline) != 0)
63+
{
64+
options = options & ~RegexOptions.Multiline;
65+
flags += "m";
66+
}
67+
68+
if ((options & RegexOptions.Singleline) != 0)
69+
{
70+
options = options & ~RegexOptions.Singleline;
71+
flags += "s";
72+
}
73+
74+
Debug.Assert(options == RegexOptions.None);
75+
76+
return flags;
77+
}
2578
}

0 commit comments

Comments
 (0)