diff --git a/src/Fable.Build/Test/JavaScript.fs b/src/Fable.Build/Test/JavaScript.fs index 27767341a..57d7a3809 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 mochaBin = 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 mochaBin |> 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 mochaBin |> 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/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..2a8f12a81 100644 --- a/tests/Js/Main/RegexTests.fs +++ b/tests/Js/Main/RegexTests.fs @@ -37,6 +37,37 @@ 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 '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 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" + // sameResult multilineignorecase "^bc" "ab\ncd" + + testCase "Regex.IsMatch with IgnoreCase and Multiline works" <| fun _ -> let str = "ab\ncd" let option1 = RegexOptions.IgnoreCase