From bfb31581910470b60e694963566c3a6358bb0f01 Mon Sep 17 00:00:00 2001 From: ieviev Date: Thu, 24 Apr 2025 15:30:01 +0300 Subject: [PATCH 1/3] Allow RegexOptions.NonBacktracking as 'l' flag --- src/fable-library-ts/RegExp.ts | 13 +++++++++---- tests/Js/Main/RegexTests.fs | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/fable-library-ts/RegExp.ts b/src/fable-library-ts/RegExp.ts index 39999d2ed..924791d0e 100644 --- a/src/fable-library-ts/RegExp.ts +++ b/src/fable-library-ts/RegExp.ts @@ -7,11 +7,16 @@ export function create(pattern: string, options = 0) { // * Compiled: 0x0008 (ignored) // * Singleline: 0x0010 // * ECMAScript: 0x0100 (ignored) - if ((options & ~(1 ^ 2 ^ 8 ^ 16 ^ 256)) !== 0) { - throw new Error("RegexOptions only supports: IgnoreCase, Multiline, Compiled, Singleline and ECMAScript"); + // * NonBacktracking: 0x0400 + if ((options & ~(1 ^ 2 ^ 8 ^ 16 ^ 256 ^ 1024)) !== 0) { + throw new Error("RegexOptions only supports: IgnoreCase, Multiline, Compiled, Singleline, ECMAScript and NonBacktracking"); } - // Set always global and unicode flags for compatibility with dotnet, see #2925 - let flags = "gu"; + + let flags = ""; + // Set global and unicode flags for compatibility with dotnet, see #2925 + // for NonBacktracking, add just 'l', ('u' + 'l' is unsupported, 'g' + 'l' + // is supported only with '--enable-experimental-regexp-engine') + flags += options & 1024 ? "l" : "gu"; flags += options & 1 ? "i" : ""; // 0x0001 RegexOptions.IgnoreCase flags += options & 2 ? "m" : ""; flags += options & 16 ? "s" : ""; diff --git a/tests/Js/Main/RegexTests.fs b/tests/Js/Main/RegexTests.fs index d30892485..c4b6d75ad 100644 --- a/tests/Js/Main/RegexTests.fs +++ b/tests/Js/Main/RegexTests.fs @@ -37,6 +37,32 @@ let tests = let r = Regex("[a-z]", options) int r.Options |> equal 257 + testCase "RegexOptions.NonBacktracking = 1024" <| fun _ -> + let options = RegexOptions.NonBacktracking + int options |> equal 1024 + + // these tests depend on '--enable-experimental-regexp-engine' or + // an newer version of V8 that supports 'l' flag + // the tests are ascii only, 'l' and 'u' together are not supported + // testCase "Nonbacktracking regex tests" <| fun _ -> + // let none = RegexOptions.None + // let nonb = RegexOptions.NonBacktracking + // let multiline = RegexOptions.Multiline + // let ignorecase = RegexOptions.IgnoreCase + // let multilineignorecase = multiline ||| ignorecase + // let str = "For more information, see Chapter 3.4.5.1" + // let sameResult extraopts str pat = + // let result1 = Regex.Match(str, pat, none ||| extraopts).Success + // let result2 = Regex.Match(str, pat, nonb ||| extraopts).Success + // equal result1 result2 + // sameResult none str "Chapter \d+(\.\d)*" + // sameResult none str "chapter \d+(\.\d)*" + // sameResult multilineignorecase "^ab" "ab\ncd" + // sameResult multilineignorecase "^cd" "ab\ncd" + // sameResult multilineignorecase "^AB" "ab\ncd" + // sameResult multilineignorecase "^bc" "ab\ncd" + + testCase "Regex.IsMatch with IgnoreCase and Multiline works" <| fun _ -> let str = "ab\ncd" let option1 = RegexOptions.IgnoreCase From 04d1bd214893c40e32e6056a0dd1f064c7dd4321 Mon Sep 17 00:00:00 2001 From: ieviev Date: Tue, 29 Apr 2025 23:50:27 +0300 Subject: [PATCH 2/3] passing --enable-experimental-regexp-engine to mocha --- src/Fable.Build/Test/JavaScript.fs | 35 ++++++++++++++++++++---------- tests/Js/Main/RegexTests.fs | 33 ++++++++++++++++------------ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/Fable.Build/Test/JavaScript.fs b/src/Fable.Build/Test/JavaScript.fs index 27767341a..1a150a419 100644 --- a/src/Fable.Build/Test/JavaScript.fs +++ b/src/Fable.Build/Test/JavaScript.fs @@ -10,10 +10,11 @@ open SimpleExec let private mainTestSourceDir = Path.Resolve("tests", "Js", "Main") -let private mainTestProject = - Path.Resolve("tests", "Js", "Main", "Fable.Tests.fsproj") +let private mainTestProject = Path.Resolve("tests", "Js", "Main", "Fable.Tests.fsproj") -let private testReact (isWatch: bool) = +let private mocha_bin = Path.Resolve("node_modules", ".bin", "mocha") + +let private testReact(isWatch: bool) = let workingDirectory = Path.Resolve("tests", "React") Command.Run("npm", "install", workingDirectory = workingDirectory) @@ -21,7 +22,10 @@ let private testReact (isWatch: bool) = if isWatch then Async.Parallel [ - Command.WatchFableAsync(CmdLine.appendRaw "--noCache", workingDirectory = workingDirectory) + Command.WatchFableAsync( + CmdLine.appendRaw "--noCache", + workingDirectory = workingDirectory + ) |> Async.AwaitTask Command.RunAsync("npx", "jest --watch", workingDirectory = workingDirectory) @@ -34,7 +38,7 @@ let private testReact (isWatch: bool) = Command.Run("npx", "jest", workingDirectory = workingDirectory) -let private testAdaptive (isWatch: bool) = +let private testAdaptive(isWatch: bool) = let folderName = "Adaptive" let sourceDir = Path.Resolve("tests", "Js", folderName) @@ -42,8 +46,9 @@ let private testAdaptive (isWatch: bool) = let mochaCommand = CmdLine.empty - |> CmdLine.appendRaw "npx" - |> CmdLine.appendRaw "mocha" + |> CmdLine.appendRaw "node" + |> CmdLine.appendRaw "--enable-experimental-regexp-engine" + |> CmdLine.appendRaw mocha_bin |> CmdLine.appendRaw destinationDir |> CmdLine.appendPrefix "--reporter" "dot" |> CmdLine.appendPrefix "-t" "10000" @@ -83,8 +88,9 @@ let private handleMainTests (isWatch: bool) (noDotnet: bool) = let mochaCommand = CmdLine.empty - |> CmdLine.appendRaw "npx" - |> CmdLine.appendRaw "mocha" + |> CmdLine.appendRaw "node" + |> CmdLine.appendRaw "--enable-experimental-regexp-engine" + |> CmdLine.appendRaw mocha_bin |> CmdLine.appendRaw destinationDir |> CmdLine.appendPrefix "--reporter" "dot" |> CmdLine.appendPrefix "-t" "10000" @@ -129,7 +135,11 @@ let private handleMainTests (isWatch: bool) (noDotnet: bool) = |> Async.RunSynchronously |> ignore else - Command.Run("dotnet", "run -c Release", workingDirectory = Path.Combine("tests", "Js", "Main")) + Command.Run( + "dotnet", + "run -c Release", + workingDirectory = Path.Combine("tests", "Js", "Main") + ) // Test the Main tests against JavaScript Command.Fable(fableArgs, workingDirectory = destinationDir) @@ -143,7 +153,7 @@ let private handleMainTests (isWatch: bool) (noDotnet: bool) = // if isCI.IsSome then // Standalone.handleStandaloneFast () -let handle (args: string list) = +let handle(args: string list) = let isReactOnly = args |> List.contains "--react-only" let isStandaloneOnly = args |> List.contains "--standalone-only" let isAdaptiveOnly = args |> List.contains "--adaptive-only" @@ -155,7 +165,8 @@ let handle (args: string list) = | (true, true, _) | (true, _, true) | (_, true, true) -> - failwith "Cannot use '--react-only', '--standalone-only' and '--adaptive-only' at the same time" + failwith + "Cannot use '--react-only', '--standalone-only' and '--adaptive-only' at the same time" | _ -> () diff --git a/tests/Js/Main/RegexTests.fs b/tests/Js/Main/RegexTests.fs index c4b6d75ad..2a8f12a81 100644 --- a/tests/Js/Main/RegexTests.fs +++ b/tests/Js/Main/RegexTests.fs @@ -41,22 +41,27 @@ let tests = let options = RegexOptions.NonBacktracking int options |> equal 1024 - // these tests depend on '--enable-experimental-regexp-engine' or - // an newer version of V8 that supports 'l' flag - // the tests are ascii only, 'l' and 'u' together are not supported - // testCase "Nonbacktracking regex tests" <| fun _ -> - // let none = RegexOptions.None - // let nonb = RegexOptions.NonBacktracking - // let multiline = RegexOptions.Multiline + // these tests depend on 'node --enable-experimental-regexp-engine' or + // a newer version of V8 that supports 'l' flag + // /lu (with unicode) is not supported + // /lm (with multiline) is not supported + testCase "Nonbacktracking regex tests" <| fun _ -> + let none = RegexOptions.None + let nonb = RegexOptions.NonBacktracking // let ignorecase = RegexOptions.IgnoreCase // let multilineignorecase = multiline ||| ignorecase - // let str = "For more information, see Chapter 3.4.5.1" - // let sameResult extraopts str pat = - // let result1 = Regex.Match(str, pat, none ||| extraopts).Success - // let result2 = Regex.Match(str, pat, nonb ||| extraopts).Success - // equal result1 result2 - // sameResult none str "Chapter \d+(\.\d)*" - // sameResult none str "chapter \d+(\.\d)*" + + let sameResult extraopts str pat = + let result1 = Regex.Match(str, pat, none ||| extraopts).Success + let result2 = Regex.Match(str, pat, nonb ||| extraopts).Success + equal result1 result2 + + let str = "For more information, see Chapter 3.4.5.1" + sameResult none str "Chapter \d+(\.\d)*" + sameResult none str "chapter \d+(\.\d)*" + + // some combinations of settings are not allowed with linear: + // Invalid regular expression: /ab\ncd/ilm: Cannot be executed in linear time // sameResult multilineignorecase "^ab" "ab\ncd" // sameResult multilineignorecase "^cd" "ab\ncd" // sameResult multilineignorecase "^AB" "ab\ncd" From c014486287e5219516d30e97cad2d035e071bfc3 Mon Sep 17 00:00:00 2001 From: ieviev Date: Wed, 30 Apr 2025 13:10:28 +0300 Subject: [PATCH 3/3] naming --- src/Fable.Build/Test/JavaScript.fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Fable.Build/Test/JavaScript.fs b/src/Fable.Build/Test/JavaScript.fs index 1a150a419..57d7a3809 100644 --- a/src/Fable.Build/Test/JavaScript.fs +++ b/src/Fable.Build/Test/JavaScript.fs @@ -12,7 +12,7 @@ let private mainTestSourceDir = Path.Resolve("tests", "Js", "Main") let private mainTestProject = Path.Resolve("tests", "Js", "Main", "Fable.Tests.fsproj") -let private mocha_bin = Path.Resolve("node_modules", ".bin", "mocha") +let private mochaBin = Path.Resolve("node_modules", ".bin", "mocha") let private testReact(isWatch: bool) = let workingDirectory = Path.Resolve("tests", "React") @@ -48,7 +48,7 @@ let private testAdaptive(isWatch: bool) = CmdLine.empty |> CmdLine.appendRaw "node" |> CmdLine.appendRaw "--enable-experimental-regexp-engine" - |> CmdLine.appendRaw mocha_bin + |> CmdLine.appendRaw mochaBin |> CmdLine.appendRaw destinationDir |> CmdLine.appendPrefix "--reporter" "dot" |> CmdLine.appendPrefix "-t" "10000" @@ -90,7 +90,7 @@ let private handleMainTests (isWatch: bool) (noDotnet: bool) = CmdLine.empty |> CmdLine.appendRaw "node" |> CmdLine.appendRaw "--enable-experimental-regexp-engine" - |> CmdLine.appendRaw mocha_bin + |> CmdLine.appendRaw mochaBin |> CmdLine.appendRaw destinationDir |> CmdLine.appendPrefix "--reporter" "dot" |> CmdLine.appendPrefix "-t" "10000"