diff --git a/dotnet/BUILD.bazel b/dotnet/BUILD.bazel
index 44ded9c69201b..da92a9358747b 100644
--- a/dotnet/BUILD.bazel
+++ b/dotnet/BUILD.bazel
@@ -26,3 +26,12 @@ pkg_zip(
"release-artifact",
],
)
+
+filegroup(
+ name = "source_files_support_needs_from_core",
+ srcs = [
+ "//dotnet/src/webdriver:Internal/StringSyntaxAttribute.cs",
+ "//dotnet/src/webdriver:Internal/StringSyntaxConstants.cs",
+ ],
+ visibility = ["__subpackages__"],
+)
diff --git a/dotnet/src/support/BUILD.bazel b/dotnet/src/support/BUILD.bazel
index 930e842870ee8..9cc66665c7618 100644
--- a/dotnet/src/support/BUILD.bazel
+++ b/dotnet/src/support/BUILD.bazel
@@ -32,7 +32,10 @@ csharp_library(
"Events/*.cs",
"Extensions/*.cs",
"UI/*.cs",
- ]) + [":assembly-info"],
+ ]) + [
+ ":assembly-info",
+ "//dotnet:source_files_support_needs_from_core",
+ ],
out = "WebDriver.Support",
langversion = "12.0",
nullable = "enable",
@@ -71,7 +74,10 @@ csharp_library(
"Events/*.cs",
"Extensions/*.cs",
"UI/*.cs",
- ]) + [":assembly-info"],
+ ]) + [
+ ":assembly-info",
+ "//dotnet:source_files_support_needs_from_core",
+ ],
out = "WebDriver.Support.StrongNamed",
keyfile = "//dotnet:Selenium.snk",
langversion = "12.0",
diff --git a/dotnet/src/support/Events/EventFiringWebDriver.cs b/dotnet/src/support/Events/EventFiringWebDriver.cs
index a23c4a04bf9ed..974843dbce1e4 100644
--- a/dotnet/src/support/Events/EventFiringWebDriver.cs
+++ b/dotnet/src/support/Events/EventFiringWebDriver.cs
@@ -20,8 +20,10 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Threading.Tasks;
+using OpenQA.Selenium.Internal;
namespace OpenQA.Selenium.Support.Events;
@@ -442,7 +444,7 @@ public void Dispose()
/// variable, as if the function were called via "Function.apply"
///
///
- public object? ExecuteScript(string script, params object?[] args)
+ public object? ExecuteScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args)
{
if (this.WrappedDriver is not IJavaScriptExecutor javascriptDriver)
{
@@ -542,7 +544,7 @@ public void Dispose()
/// The JavaScript code to execute.
/// The arguments to the script.
/// The value returned by the script.
- public object? ExecuteAsyncScript(string script, params object?[] args)
+ public object? ExecuteAsyncScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args)
{
if (this.WrappedDriver is not IJavaScriptExecutor javascriptDriver)
{
diff --git a/dotnet/src/support/Events/WebDriverScriptEventArgs.cs b/dotnet/src/support/Events/WebDriverScriptEventArgs.cs
index be198ecf62945..ab9bfd254eccb 100644
--- a/dotnet/src/support/Events/WebDriverScriptEventArgs.cs
+++ b/dotnet/src/support/Events/WebDriverScriptEventArgs.cs
@@ -18,6 +18,8 @@
//
using System;
+using System.Diagnostics.CodeAnalysis;
+using OpenQA.Selenium.Internal;
namespace OpenQA.Selenium.Support.Events;
@@ -32,7 +34,7 @@ public class WebDriverScriptEventArgs : EventArgs
/// The WebDriver instance used to execute the script.
/// The script executed by the driver.
/// If or are .
- public WebDriverScriptEventArgs(IWebDriver driver, string script)
+ public WebDriverScriptEventArgs(IWebDriver driver, [StringSyntax(StringSyntaxConstants.JavaScript)] string script)
{
this.Driver = driver ?? throw new ArgumentNullException(nameof(driver));
this.Script = script ?? throw new ArgumentNullException(nameof(script));
diff --git a/dotnet/src/support/Extensions/WebDriverExtensions.cs b/dotnet/src/support/Extensions/WebDriverExtensions.cs
index 8ef995719dfda..64b81bdc62caa 100644
--- a/dotnet/src/support/Extensions/WebDriverExtensions.cs
+++ b/dotnet/src/support/Extensions/WebDriverExtensions.cs
@@ -18,7 +18,9 @@
//
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
+using OpenQA.Selenium.Internal;
namespace OpenQA.Selenium.Support.Extensions;
@@ -71,7 +73,7 @@ public static Screenshot TakeScreenshot(this IWebDriver driver)
/// The arguments to the script.
/// Thrown if this instance
/// does not implement
- public static void ExecuteJavaScript(this IWebDriver driver, string script, params object?[] args)
+ public static void ExecuteJavaScript(this IWebDriver driver, [StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args)
{
ExecuteJavaScriptInternal(driver, script, args);
}
@@ -87,7 +89,7 @@ public static void ExecuteJavaScript(this IWebDriver driver, string script, para
/// Thrown if this instance
/// does not implement , or if the actual return type
/// of the JavaScript execution does not match the expected type.
- public static T? ExecuteJavaScript(this IWebDriver driver, string script, params object?[] args)
+ public static T? ExecuteJavaScript(this IWebDriver driver, [StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args)
{
var value = ExecuteJavaScriptInternal(driver, script, args);
if (value == null)
diff --git a/dotnet/src/support/Selenium.WebDriver.Support.csproj b/dotnet/src/support/Selenium.WebDriver.Support.csproj
index 1ddf670d553c8..9c0e10cd7a79e 100644
--- a/dotnet/src/support/Selenium.WebDriver.Support.csproj
+++ b/dotnet/src/support/Selenium.WebDriver.Support.csproj
@@ -40,4 +40,10 @@
+
+
+
+
+
+
diff --git a/dotnet/src/webdriver/BUILD.bazel b/dotnet/src/webdriver/BUILD.bazel
index 0d57751f521e1..2d6a8735d4e77 100644
--- a/dotnet/src/webdriver/BUILD.bazel
+++ b/dotnet/src/webdriver/BUILD.bazel
@@ -12,6 +12,8 @@ load(
exports_files([
"WebDriver.csproj",
+ "Internal/StringSyntaxAttribute.cs",
+ "Internal/StringSyntaxConstants.cs",
])
generated_assembly_info(
diff --git a/dotnet/src/webdriver/DevTools/JavaScript.cs b/dotnet/src/webdriver/DevTools/JavaScript.cs
index 5ef23219b5563..69f488397754d 100644
--- a/dotnet/src/webdriver/DevTools/JavaScript.cs
+++ b/dotnet/src/webdriver/DevTools/JavaScript.cs
@@ -18,7 +18,9 @@
//
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
+using OpenQA.Selenium.Internal;
namespace OpenQA.Selenium.DevTools;
@@ -85,7 +87,7 @@ public abstract class JavaScript
///
/// The script to add to be evaluated when a new document is opened.
/// A task that represents the asynchronous operation. The task result contains the internal ID of the script.
- public abstract Task AddScriptToEvaluateOnNewDocument(string script);
+ public abstract Task AddScriptToEvaluateOnNewDocument([StringSyntax(StringSyntaxConstants.JavaScript)] string script);
///
/// Removes a JavaScript snippet from evaluate when a new document is opened.
@@ -103,7 +105,7 @@ public abstract class JavaScript
/// This method is internal to the operation of pinned scripts in Selenium, and
/// is therefore internal by design.
///
- internal abstract Task Evaluate(string script);
+ internal abstract Task Evaluate([StringSyntax(StringSyntaxConstants.JavaScript)] string script);
///
/// Raises the BindingCalled event.
diff --git a/dotnet/src/webdriver/IJavaScriptEngine.cs b/dotnet/src/webdriver/IJavaScriptEngine.cs
index 0ae8bf8cafb7f..2dd71d6bc1fd8 100644
--- a/dotnet/src/webdriver/IJavaScriptEngine.cs
+++ b/dotnet/src/webdriver/IJavaScriptEngine.cs
@@ -19,7 +19,9 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
+using OpenQA.Selenium.Internal;
namespace OpenQA.Selenium;
@@ -88,7 +90,7 @@ public interface IJavaScriptEngine : IDisposable
/// The JavaScript to be loaded on every page.
/// A task containing an object representing the script to be loaded on each page.
/// If or are .
- Task AddInitializationScript(string scriptName, string script);
+ Task AddInitializationScript(string scriptName, [StringSyntax(StringSyntaxConstants.JavaScript)] string script);
///
/// Asynchronously removes JavaScript from being loaded on every document load.
@@ -112,7 +114,7 @@ public interface IJavaScriptEngine : IDisposable
/// The JavaScript to pin
/// A task containing a object to use to execute the script.
/// If is .
- Task PinScript(string script);
+ Task PinScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script);
///
/// Unpins a previously pinned script from the browser.
diff --git a/dotnet/src/webdriver/IJavascriptExecutor.cs b/dotnet/src/webdriver/IJavascriptExecutor.cs
index 5b1fe570e02b3..9f4de14c29c32 100644
--- a/dotnet/src/webdriver/IJavascriptExecutor.cs
+++ b/dotnet/src/webdriver/IJavascriptExecutor.cs
@@ -19,6 +19,8 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using OpenQA.Selenium.Internal;
namespace OpenQA.Selenium;
@@ -62,7 +64,7 @@ public interface IJavaScriptExecutor
/// variable, as if the function were called via "Function.apply"
///
///
- object? ExecuteScript(string script, params object?[] args);
+ object? ExecuteScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args);
///
/// Executes JavaScript in the context of the currently selected frame or window.
@@ -108,5 +110,5 @@ public interface IJavaScriptExecutor
/// The JavaScript code to execute.
/// The arguments to the script.
/// The value returned by the script.
- object? ExecuteAsyncScript(string script, params object?[] args);
+ object? ExecuteAsyncScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args);
}
diff --git a/dotnet/src/webdriver/InitializationScript.cs b/dotnet/src/webdriver/InitializationScript.cs
index 189cf02b88888..6cf16079c68ac 100644
--- a/dotnet/src/webdriver/InitializationScript.cs
+++ b/dotnet/src/webdriver/InitializationScript.cs
@@ -18,7 +18,9 @@
//
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
+using OpenQA.Selenium.Internal;
namespace OpenQA.Selenium;
@@ -47,6 +49,7 @@ internal InitializationScript(string scriptId, string scriptName, string scriptS
///
/// Gets the JavaScript source of the initialization script.
///
+ [StringSyntax(StringSyntaxConstants.JavaScript)]
public string ScriptSource { get; }
///
diff --git a/dotnet/src/webdriver/Internal/FileUtilities.cs b/dotnet/src/webdriver/Internal/FileUtilities.cs
index 1603cdbde8ea5..e74dcabc0a93b 100644
--- a/dotnet/src/webdriver/Internal/FileUtilities.cs
+++ b/dotnet/src/webdriver/Internal/FileUtilities.cs
@@ -19,6 +19,7 @@
using OpenQA.Selenium.Internal.Logging;
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Reflection;
@@ -209,11 +210,7 @@ public static string GetCurrentDirectory()
/// The pattern to use in creating the directory name, following standard
/// .NET string replacement tokens.
/// The full path to the random directory name in the temporary directory.
- public static string GenerateRandomTempDirectoryName(
-#if NET8_0_OR_GREATER
- [System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.CompositeFormat)]
-#endif
- string directoryPattern)
+ public static string GenerateRandomTempDirectoryName([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string directoryPattern)
{
string directoryName = string.Format(CultureInfo.InvariantCulture, directoryPattern, Guid.NewGuid().ToString("N"));
return Path.Combine(Path.GetTempPath(), directoryName);
diff --git a/dotnet/src/webdriver/Internal/StringSyntaxAttribute.cs b/dotnet/src/webdriver/Internal/StringSyntaxAttribute.cs
new file mode 100644
index 0000000000000..bbb12f6a804b1
--- /dev/null
+++ b/dotnet/src/webdriver/Internal/StringSyntaxAttribute.cs
@@ -0,0 +1,89 @@
+//
+// Licensed to the Software Freedom Conservancy (SFC) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The SFC licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+#if !NET8_0_OR_GREATER
+
+namespace System.Diagnostics.CodeAnalysis;
+
+/// Specifies the syntax used in a string.
+[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
+internal sealed class StringSyntaxAttribute : Attribute
+{
+ /// Initializes the with the identifier of the syntax used.
+ /// The syntax identifier.
+ public StringSyntaxAttribute(string syntax)
+ {
+ Syntax = syntax;
+ Arguments = [];
+ }
+
+ /// Initializes the with the identifier of the syntax used.
+ /// The syntax identifier.
+ /// Optional arguments associated with the specific syntax employed.
+ public StringSyntaxAttribute(string syntax, params object?[] arguments)
+ {
+ Syntax = syntax;
+ Arguments = arguments;
+ }
+
+ /// Gets the identifier of the syntax used.
+ public string Syntax { get; }
+
+ /// Optional arguments associated with the specific syntax employed.
+ public object?[] Arguments { get; }
+
+ /// The syntax identifier for strings containing composite formats for string formatting.
+ public const string CompositeFormat = nameof(CompositeFormat);
+
+ /// The syntax identifier for strings containing date format specifiers.
+ public const string DateOnlyFormat = nameof(DateOnlyFormat);
+
+ /// The syntax identifier for strings containing date and time format specifiers.
+ public const string DateTimeFormat = nameof(DateTimeFormat);
+
+ /// The syntax identifier for strings containing format specifiers.
+ public const string EnumFormat = nameof(EnumFormat);
+
+ /// The syntax identifier for strings containing format specifiers.
+ public const string GuidFormat = nameof(GuidFormat);
+
+ /// The syntax identifier for strings containing JavaScript Object Notation (JSON).
+ public const string Json = nameof(Json);
+
+ /// The syntax identifier for strings containing numeric format specifiers.
+ public const string NumericFormat = nameof(NumericFormat);
+
+ /// The syntax identifier for strings containing regular expressions.
+ public const string Regex = nameof(Regex);
+
+ /// The syntax identifier for strings containing time format specifiers.
+ public const string TimeOnlyFormat = nameof(TimeOnlyFormat);
+
+ /// The syntax identifier for strings containing format specifiers.
+ public const string TimeSpanFormat = nameof(TimeSpanFormat);
+
+ /// The syntax identifier for strings containing URIs.
+ public const string Uri = nameof(Uri);
+
+ /// The syntax identifier for strings containing XML.
+ public const string Xml = nameof(Xml);
+}
+
+#endif
+
diff --git a/dotnet/src/webdriver/Internal/StringSyntaxConstants.cs b/dotnet/src/webdriver/Internal/StringSyntaxConstants.cs
new file mode 100644
index 0000000000000..55547e66244bc
--- /dev/null
+++ b/dotnet/src/webdriver/Internal/StringSyntaxConstants.cs
@@ -0,0 +1,25 @@
+//
+// Licensed to the Software Freedom Conservancy (SFC) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The SFC licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+namespace OpenQA.Selenium.Internal;
+
+internal static class StringSyntaxConstants
+{
+ public const string JavaScript = "javascript";
+}
diff --git a/dotnet/src/webdriver/JavaScriptEngine.cs b/dotnet/src/webdriver/JavaScriptEngine.cs
index d44f786a06943..86f20c64c6f2c 100644
--- a/dotnet/src/webdriver/JavaScriptEngine.cs
+++ b/dotnet/src/webdriver/JavaScriptEngine.cs
@@ -164,7 +164,7 @@ public async Task DisableDomMutationMonitoring()
/// The JavaScript to be loaded on every page.
/// A task containing an object representing the script to be loaded on each page.
/// If or are .
- public async Task AddInitializationScript(string scriptName, string script)
+ public async Task AddInitializationScript(string scriptName, [StringSyntax(StringSyntaxConstants.JavaScript)] string script)
{
if (scriptName is null)
{
@@ -233,7 +233,7 @@ public async Task ClearInitializationScripts()
/// The JavaScript to pin
/// A task containing a object to use to execute the script.
/// If is .
- public async Task PinScript(string script)
+ public async Task PinScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script)
{
if (script == null)
{
diff --git a/dotnet/src/webdriver/PinnedScript.cs b/dotnet/src/webdriver/PinnedScript.cs
index 158f7683c9fdd..a51fea3d0cc60 100644
--- a/dotnet/src/webdriver/PinnedScript.cs
+++ b/dotnet/src/webdriver/PinnedScript.cs
@@ -17,7 +17,9 @@
// under the License.
//
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
+using OpenQA.Selenium.Internal;
namespace OpenQA.Selenium;
@@ -53,6 +55,7 @@ internal PinnedScript(string script, string stringHandle, string scriptId)
///
/// Gets the source representing the body of the function in the pinned script.
///
+ [StringSyntax(StringSyntaxConstants.JavaScript)]
public string Source { get; }
internal static string MakeCreationScript(string scriptHandle, string scriptSource)
diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs
index 77f82461053d7..45181ed88a2c0 100644
--- a/dotnet/src/webdriver/WebDriver.cs
+++ b/dotnet/src/webdriver/WebDriver.cs
@@ -234,7 +234,7 @@ public void Dispose()
/// The JavaScript code to execute.
/// The arguments to the script.
/// The value returned by the script.
- public object? ExecuteAsyncScript(string script, params object?[]? args)
+ public object? ExecuteAsyncScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[]? args)
{
return this.ExecuteScriptCommand(script, DriverCommand.ExecuteAsyncScript, args);
}
@@ -245,7 +245,7 @@ public void Dispose()
/// The JavaScript code to execute.
/// The arguments to the script.
/// The value returned by the script.
- public object? ExecuteScript(string script, params object?[]? args)
+ public object? ExecuteScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[]? args)
{
return this.ExecuteScriptCommand(script, DriverCommand.ExecuteScript, args);
}
@@ -834,7 +834,7 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command
/// The name of the command to execute.
/// The arguments to the script.
/// The value returned by the script.
- protected object? ExecuteScriptCommand(string script, string commandName, params object?[]? args)
+ protected object? ExecuteScriptCommand([StringSyntax(StringSyntaxConstants.JavaScript)] string script, string commandName, params object?[]? args)
{
object?[] convertedArgs = ConvertArgumentsToJavaScriptObjects(args);