From 3c9c5c096a2929ec08dd8221f9f5ccc4b9ef35e6 Mon Sep 17 00:00:00 2001 From: Goswin Rothenthal Date: Wed, 18 Sep 2024 18:08:35 +0200 Subject: [PATCH 1/3] OrdinalIgnoreCase for EndsWith --- src/fable-library-ts/String.ts | 8 +++++--- tests/Js/Main/StringTests.fs | 11 +++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/fable-library-ts/String.ts b/src/fable-library-ts/String.ts index 925ca8a32a..469aa6affa 100644 --- a/src/fable-library-ts/String.ts +++ b/src/fable-library-ts/String.ts @@ -374,9 +374,11 @@ export function format(str: string | object, ...args: any[]) { }); } -export function endsWith(str: string, search: string) { - const idx = str.lastIndexOf(search); - return idx >= 0 && idx === str.length - search.length; +export function endsWith(str: string, pattern: string, ic: number) { + if (str.length >= pattern.length) { + return cmp(str.substr(str.length-1-pattern.length, pattern.length), pattern, ic) === 0; + } + return false; } export function initialize(n: number, f: (i: number) => string) { diff --git a/tests/Js/Main/StringTests.fs b/tests/Js/Main/StringTests.fs index 6c2a79eff5..8a598c5a7c 100644 --- a/tests/Js/Main/StringTests.fs +++ b/tests/Js/Main/StringTests.fs @@ -820,8 +820,8 @@ let tests = testList "Strings" [ "abcd".StartsWith(fst arg) |> equal (snd arg) - testCase "String.StartsWith with StringComparison works" <| fun () -> - let args = [("ab", true); ("cd", false); ("abcdx", false)] + testCase "String.StartsWith with StringComparison.OrdinalIgnoreCase works" <| fun () -> + let args = [("ab", true); ("AB", true); ("cd", false); ("abcd", false)] for arg in args do "ABCD".StartsWith(fst arg, StringComparison.OrdinalIgnoreCase) |> equal (snd arg) @@ -833,6 +833,13 @@ let tests = testList "Strings" [ "abcd".EndsWith(fst arg) |> equal (snd arg) + testCase "String.EndsWith with StringComparison.OrdinalIgnoreCase works" <| fun () -> + let args = [("ab", false); ("CD", true); ("cd", true); ("abcd", false)] + for arg in args do + "ABCD".EndsWith(fst arg, StringComparison.OrdinalIgnoreCase) + |> equal (snd arg) + + testCase "String.Trim works" <| fun () -> " abc ".Trim() |> equal "abc" From 72fe81973c3632ad6dedfb14db45a15c66fb5d89 Mon Sep 17 00:00:00 2001 From: Goswin Rothenthal Date: Wed, 18 Sep 2024 20:11:56 +0200 Subject: [PATCH 2/3] use Transformer Replacements --- build.sh | 2 ++ src/Fable.Transforms/Replacements.fs | 10 ++++++---- src/fable-library-ts/String.ts | 19 +++++++++++++------ 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/build.sh b/build.sh index 807a756d27..31bbad200e 100755 --- a/build.sh +++ b/build.sh @@ -2,3 +2,5 @@ dotnet tool restore dotnet run --project src/Fable.Build/Fable.Build.fsproj -- $@ +# dotnet run --project src/Fable.Build/Fable.Build.fsproj -- test javascript +# dotnet run --project src/Fable.Build/Fable.Build.fsproj -- test typescript diff --git a/src/Fable.Transforms/Replacements.fs b/src/Fable.Transforms/Replacements.fs index efce42c565..f281afb382 100644 --- a/src/Fable.Transforms/Replacements.fs +++ b/src/Fable.Transforms/Replacements.fs @@ -1449,7 +1449,6 @@ let implementedStringFunctions = [| "Compare" "CompareTo" - "EndsWith" "Format" "IndexOfAny" "Insert" @@ -1503,12 +1502,15 @@ let strings (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr opt let left = Helper.InstanceCall(c, "indexOf", Int32.Number, [ arg ]) makeEqOp r left (makeIntConst 0) BinaryGreaterOrEqual |> Some - | "StartsWith", Some c, [ _str ] -> - let left = Helper.InstanceCall(c, "indexOf", Int32.Number, args) - makeEqOp r left (makeIntConst 0) BinaryEqual |> Some + | "StartsWith", Some c, [ _str ] -> Helper.InstanceCall(c, "startsWith", Boolean, args) |> Some | "StartsWith", Some c, [ _str; _comp ] -> Helper.LibCall(com, "String", "startsWith", t, args, i.SignatureArgTypes, thisArg = c, ?loc = r) |> Some + | "EndsWith", Some c, [ _str ] -> Helper.InstanceCall(c, "endsWith", Boolean, args) |> Some + | "EndsWith", Some c, [ _str; _comp ] -> + Helper.LibCall(com, "String", "endsWith", t, args, i.SignatureArgTypes, thisArg = c, ?loc = r) + |> Some + | ReplaceName [ "ToUpper", "toLocaleUpperCase" "ToUpperInvariant", "toUpperCase" "ToLower", "toLocaleLowerCase" diff --git a/src/fable-library-ts/String.ts b/src/fable-library-ts/String.ts index 469aa6affa..994581428e 100644 --- a/src/fable-library-ts/String.ts +++ b/src/fable-library-ts/String.ts @@ -64,12 +64,25 @@ export function compareTo(x: string, y: string) { } export function startsWith(str: string, pattern: string, ic: number) { + if (ic=== StringComparison.Ordinal){ // to avoid substring allocation + return str.startsWith(pattern) ; + } if (str.length >= pattern.length) { return cmp(str.substr(0, pattern.length), pattern, ic) === 0; } return false; } +export function endsWith(str: string, pattern: string, ic: number) { + if (ic=== StringComparison.Ordinal){ // to avoid substring allocation + return str.endsWith(pattern) ; + } + if (str.length >= pattern.length) { + return cmp(str.substr(str.length-pattern.length, pattern.length), pattern, ic) === 0; + } + return false; +} + export function indexOfAny(str: string, anyOf: string[], ...args: number[]) { if (str == null || str === "") { return -1; @@ -374,12 +387,6 @@ export function format(str: string | object, ...args: any[]) { }); } -export function endsWith(str: string, pattern: string, ic: number) { - if (str.length >= pattern.length) { - return cmp(str.substr(str.length-1-pattern.length, pattern.length), pattern, ic) === 0; - } - return false; -} export function initialize(n: number, f: (i: number) => string) { if (n < 0) { From cc914e5a7b410ec4e73bde9d684c696ac450e62d Mon Sep 17 00:00:00 2001 From: Goswin Rothenthal Date: Wed, 18 Sep 2024 20:29:36 +0200 Subject: [PATCH 3/3] fix tests --- build.sh | 2 -- tests/Js/Main/StringTests.fs | 18 ++++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/build.sh b/build.sh index 31bbad200e..807a756d27 100755 --- a/build.sh +++ b/build.sh @@ -2,5 +2,3 @@ dotnet tool restore dotnet run --project src/Fable.Build/Fable.Build.fsproj -- $@ -# dotnet run --project src/Fable.Build/Fable.Build.fsproj -- test javascript -# dotnet run --project src/Fable.Build/Fable.Build.fsproj -- test typescript diff --git a/tests/Js/Main/StringTests.fs b/tests/Js/Main/StringTests.fs index 8a598c5a7c..3707d3a483 100644 --- a/tests/Js/Main/StringTests.fs +++ b/tests/Js/Main/StringTests.fs @@ -815,30 +815,28 @@ let tests = testList "Strings" [ "abcdbcebc".IndexOfAny([|'c';'b'|]) |> equal 1 testCase "String.StartsWith works" <| fun () -> - let args = [("ab", true); ("cd", false); ("abcdx", false)] + let args = [("ab", true); ("bc", false); ("cd", false); ("abcdx", false); ("abcd", true)] for arg in args do "abcd".StartsWith(fst arg) |> equal (snd arg) - testCase "String.StartsWith with StringComparison.OrdinalIgnoreCase works" <| fun () -> - let args = [("ab", true); ("AB", true); ("cd", false); ("abcd", false)] + testCase "String.StartsWith with OrdinalIgnoreCase works" <| fun () -> + let args = [("ab", true); ("AB", true); ("BC", false); ("cd", false); ("abcdx", false); ("abcd", true)] for arg in args do "ABCD".StartsWith(fst arg, StringComparison.OrdinalIgnoreCase) |> equal (snd arg) - testCase "String.EndsWith works" <| fun () -> - let args = [("ab", false); ("cd", true); ("abcdx", false)] + let args = [("ab", false); ("cd", true); ("bc", false); ("abcdx", false); ("abcd", true)] for arg in args do "abcd".EndsWith(fst arg) |> equal (snd arg) - - testCase "String.EndsWith with StringComparison.OrdinalIgnoreCase works" <| fun () -> - let args = [("ab", false); ("CD", true); ("cd", true); ("abcd", false)] + + testCase "String.EndsWith with OrdinalIgnoreCase works" <| fun () -> + let args = [("ab", false); ("CD", true); ("cd", true); ("bc", false); ("xabcd", false); ("abcd", true)] for arg in args do "ABCD".EndsWith(fst arg, StringComparison.OrdinalIgnoreCase) - |> equal (snd arg) - + |> equal (snd arg) testCase "String.Trim works" <| fun () -> " abc ".Trim()