From 9586244f55b00ce0fd75d3557c6be43fce6f9567 Mon Sep 17 00:00:00 2001 From: Hongbo Zhang Date: Thu, 19 Apr 2018 19:47:19 +0800 Subject: [PATCH 1/3] add belt.String --- jscomp/others/.depend | 1 + jscomp/others/belt_String.ml | 161 +++++++++++++++++++ jscomp/outcome_printer/outcome_printer_ns.ml | 1 + lib/4.02.3/whole_compiler.ml | 1 + lib/js/belt_String.js | 1 + 5 files changed, 165 insertions(+) create mode 100644 jscomp/others/belt_String.ml create mode 100644 lib/js/belt_String.js diff --git a/jscomp/others/.depend b/jscomp/others/.depend index 30f49d67c1..d85e05e330 100644 --- a/jscomp/others/.depend +++ b/jscomp/others/.depend @@ -55,6 +55,7 @@ belt_SetDict.cmj : belt_internalAVLset.cmj belt_Id.cmj belt_Array.cmj \ belt_SetDict.cmi belt_Map.cmj : belt_MapString.cmj belt_MapInt.cmj belt_MapDict.cmj \ belt_Id.cmj belt_Array.cmj belt_Map.cmi +belt_String.cmj : belt_internalMapInt.cmj : belt_internalAVLtree.cmj belt_SortArray.cmj \ belt_Array.cmj belt_internalMapString.cmj : belt_internalAVLtree.cmj belt_SortArray.cmj \ diff --git a/jscomp/others/belt_String.ml b/jscomp/others/belt_String.ml new file mode 100644 index 0000000000..a2e0e4f340 --- /dev/null +++ b/jscomp/others/belt_String.ml @@ -0,0 +1,161 @@ +(* Copyright (C) 2018 Authors of BuckleScript + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * In addition to the permissions granted to you by the LGPL, you may combine + * or link a "work that uses the Library" with a publicly distributed version + * of this file to produce a combined library or application, then distribute + * that combined work under the terms of your choosing, with no requirement + * to comply with the obligations normally placed on you by section 4 of the + * LGPL version 3 (or the corresponding section of a later version of the LGPL + * should you choose to use a later version). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) + +(** JavaScript String API *) + +type t = string + + +(** [concat append original] returns a new string with [append] added after [original]. + +@example {[ + concat "a" "b" = "ab";; +]} +*) +external concat : t -> t -> t = "" [@@bs.send] + +(** [concat arr original] returns a new string consisting of each item of an array of strings added to the [original] string. + +@example {[ + concatMany "1st" [|"2nd"; "3rd"; "4th"|] = "1st2nd3rd4th";; +]} +*) +external concatMany : t -> t array -> t = "concat" [@@bs.send] [@@bs.splice] + +(** ES2015: + [endsWith substr str] returns [true] if the [str] ends with [substr], [false] otherwise. + +@example {[ + endsWith "BuckleScript" "Script" = true;; + endsWith "BuckleShoes" "Script" = false;; +]} +*) +external endsWith : t -> t -> bool = "" [@@bs.send] + + +(** + [includes s searchValue ] returns [true] if [searchValue] is found anywhere within [s], [false] otherwise. + +@example {[ + includes "programmer" "gram" = true;; + includes "programmer" "er" = true;; + includes "programmer" "pro" = true;; + includes "programmer" "xyz" = false;; +]} +*) +external includes : t -> t -> bool = "" [@@bs.send] (** ES2015 *) + + + +(** + [repeat n s] returns a string that consists of [n] repetitions of [s]. Raises [RangeError] if [n] is negative. + +@example {[ + repeat "ha" 3 = "hahaha" + repeat "empty" 0 = "" +]} +*) +external repeat : t -> int -> t = "" [@@bs.send] (** ES2015 *) + +(** [replace string substr newSubstr ] returns a new string which is +identical to [string] except with the first matching instance of [substr] +replaced by [newSubstr]. + +[substr] is treated as a verbatim string to match, not a regular +expression. + +@example {[ + replace "old string" "old" "new" = "new string" + replace "the cat and the dog" "the" "this" = "this cat and the dog" +]} +*) +external replace : t -> t -> t -> t = "" [@@bs.send] + + + +(** + [split delimiter str] splits the given [str] at every occurrence of [delimiter] and returns an + array of the resulting substrings. + +@example {[ + split "2018-01-02" "-" = [|"2018"; "01"; "02"|];; + split "a,b,,c" "," = [|"a"; "b"; ""; "c"|];; + split "good::bad as great::awful" "::" = [|"good"; "bad as great"; "awful"|];; + split "has-no-delimiter" ";" = [|"has-no-delimiter"|];; +]}; +*) +external split : t -> t -> t array = "" [@@bs.send] + +(** + [splitAtMost str delimiter n] splits the given [str] at every occurrence of [delimiter] and + returns an array of the first [n] resulting substrings. If [n] is negative or greater than the + number of substrings, the array will contain all the substrings. + +@example {[ + splitAtMost "ant/bee/cat/dog/elk" "/" 3 = [|"ant"; "bee"; "cat"|];; + splitAtMost "ant/bee/cat/dog/elk" "/" 0 = [| |];; + splitAtMost "ant/bee/cat/dog/elk" "/" 9 = [|"ant"; "bee"; "cat"; "dog"; "elk"|];; +]} +*) +external splitAtMost: t -> t -> int -> t array = "split" [@@bs.send] + + +(** ES2015: + [startsWith str substr] returns [true] if the [str] starts with [substr], [false] otherwise. + +@example {[ + startsWith "BuckleScript" "Buckle" = true;; + startsWith "BuckleScript" "" = true;; + startsWith "JavaScript" "Buckle" = false;; +]} +*) +external startsWith : t -> t -> bool = "" [@@bs.send] + + +(** + [substr ~from: n str] returns the substring of [str] from position [n] to the end of the string. + + If [n] is less than zero, the starting position is the length of [str] - [n]. + + If [n] is greater than or equal to the length of [str], returns the empty string. + +@example {[ + substr ~from: 3 "abcdefghij" = "defghij" + substr ~from: (-3) "abcdefghij" = "hij" + substr ~from: 12 "abcdefghij" = "" +]} +*) +external substr : from:int -> t = "" [@@bs.send.pipe: t] + + +(** + [trim str] returns a string that is [str] with whitespace stripped from both ends. Internal whitespace is not removed. + +@example {[ + trim " abc def " = "abc def" + trim "\n\r\t abc def \n\n\t\r " = "abc def" +]} +*) +external trim : t -> t = "" [@@bs.send] + diff --git a/jscomp/outcome_printer/outcome_printer_ns.ml b/jscomp/outcome_printer/outcome_printer_ns.ml index 7c16757ff4..c499c173f0 100644 --- a/jscomp/outcome_printer/outcome_printer_ns.ml +++ b/jscomp/outcome_printer/outcome_printer_ns.ml @@ -81,6 +81,7 @@ let out_ident ppf s = | "Belt_MutableQueue" -> "Belt.MutableQueue" | "Belt_MutableStack" -> "Belt.MutableStack" + | "Belt_String" -> "Belt.String" | "Belt_List" -> "Belt.List" | "Belt_Range" -> "Belt.Range" diff --git a/lib/4.02.3/whole_compiler.ml b/lib/4.02.3/whole_compiler.ml index 628b15924e..077b1a02d2 100644 --- a/lib/4.02.3/whole_compiler.ml +++ b/lib/4.02.3/whole_compiler.ml @@ -120545,6 +120545,7 @@ let out_ident ppf s = | "Belt_MutableQueue" -> "Belt.MutableQueue" | "Belt_MutableStack" -> "Belt.MutableStack" + | "Belt_String" -> "Belt.String" | "Belt_List" -> "Belt.List" | "Belt_Range" -> "Belt.Range" diff --git a/lib/js/belt_String.js b/lib/js/belt_String.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/belt_String.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ From e74cd69224ed2b8e2012d7b3dfa7a017c067ae55 Mon Sep 17 00:00:00 2001 From: Matthias Le Brun Date: Tue, 2 Apr 2019 11:27:38 +0200 Subject: [PATCH 2/3] Updates on Belt_String Add some functions to Belt.String --- jscomp/others/belt.ml | 8 + jscomp/others/belt_String.ml | 171 +++++------------- jscomp/others/belt_String.mli | 326 ++++++++++++++++++++++++++++++++++ jscomp/others/release.ninja | 4 +- jscomp/test/bs_string_test.js | 115 +++++++++++- jscomp/test/bs_string_test.ml | 102 ++++++++++- lib/js/belt.js | 3 + lib/js/belt_String.js | 14 +- 8 files changed, 613 insertions(+), 130 deletions(-) create mode 100644 jscomp/others/belt_String.mli diff --git a/jscomp/others/belt.ml b/jscomp/others/belt.ml index ae9f1ec8e2..974bcdef1d 100644 --- a/jscomp/others/belt.ml +++ b/jscomp/others/belt.ml @@ -266,6 +266,14 @@ module Int = Belt_Int module Float = Belt_Float +(** {!Belt.String} + + Utilities for String. +*) + +module String = Belt_String + + (** {!Belt.Debug} Utilities for set up debugging diff --git a/jscomp/others/belt_String.ml b/jscomp/others/belt_String.ml index a2e0e4f340..ea6e7bc8d2 100644 --- a/jscomp/others/belt_String.ml +++ b/jscomp/others/belt_String.ml @@ -22,140 +22,61 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -(** JavaScript String API *) +(** String API *) type t = string +external length : t -> int = "length" [@@bs.get] -(** [concat append original] returns a new string with [append] added after [original]. +external get : t -> int -> t option = "%array_unsafe_get" -@example {[ - concat "a" "b" = "ab";; -]} -*) -external concat : t -> t -> t = "" [@@bs.send] +external concat : t -> t -> t = "concat" [@@bs.send] -(** [concat arr original] returns a new string consisting of each item of an array of strings added to the [original] string. - -@example {[ - concatMany "1st" [|"2nd"; "3rd"; "4th"|] = "1st2nd3rd4th";; -]} -*) external concatMany : t -> t array -> t = "concat" [@@bs.send] [@@bs.splice] -(** ES2015: - [endsWith substr str] returns [true] if the [str] ends with [substr], [false] otherwise. - -@example {[ - endsWith "BuckleScript" "Script" = true;; - endsWith "BuckleShoes" "Script" = false;; -]} -*) -external endsWith : t -> t -> bool = "" [@@bs.send] - - -(** - [includes s searchValue ] returns [true] if [searchValue] is found anywhere within [s], [false] otherwise. - -@example {[ - includes "programmer" "gram" = true;; - includes "programmer" "er" = true;; - includes "programmer" "pro" = true;; - includes "programmer" "xyz" = false;; -]} -*) -external includes : t -> t -> bool = "" [@@bs.send] (** ES2015 *) - - - -(** - [repeat n s] returns a string that consists of [n] repetitions of [s]. Raises [RangeError] if [n] is negative. - -@example {[ - repeat "ha" 3 = "hahaha" - repeat "empty" 0 = "" -]} -*) -external repeat : t -> int -> t = "" [@@bs.send] (** ES2015 *) - -(** [replace string substr newSubstr ] returns a new string which is -identical to [string] except with the first matching instance of [substr] -replaced by [newSubstr]. - -[substr] is treated as a verbatim string to match, not a regular -expression. - -@example {[ - replace "old string" "old" "new" = "new string" - replace "the cat and the dog" "the" "this" = "this cat and the dog" -]} -*) -external replace : t -> t -> t -> t = "" [@@bs.send] - - - -(** - [split delimiter str] splits the given [str] at every occurrence of [delimiter] and returns an - array of the resulting substrings. - -@example {[ - split "2018-01-02" "-" = [|"2018"; "01"; "02"|];; - split "a,b,,c" "," = [|"a"; "b"; ""; "c"|];; - split "good::bad as great::awful" "::" = [|"good"; "bad as great"; "awful"|];; - split "has-no-delimiter" ";" = [|"has-no-delimiter"|];; -]}; -*) -external split : t -> t -> t array = "" [@@bs.send] - -(** - [splitAtMost str delimiter n] splits the given [str] at every occurrence of [delimiter] and - returns an array of the first [n] resulting substrings. If [n] is negative or greater than the - number of substrings, the array will contain all the substrings. - -@example {[ - splitAtMost "ant/bee/cat/dog/elk" "/" 3 = [|"ant"; "bee"; "cat"|];; - splitAtMost "ant/bee/cat/dog/elk" "/" 0 = [| |];; - splitAtMost "ant/bee/cat/dog/elk" "/" 9 = [|"ant"; "bee"; "cat"; "dog"; "elk"|];; -]} -*) +external endsWith : t -> t -> bool = "endsWith" [@@bs.send] + +external indexOf : t -> t -> int = "indexOf" [@@bs.send] + +let indexOf s searchValue = + match indexOf s searchValue with + | -1 -> None + | value -> (Some value) + +external includes : t -> t -> bool = "includes" [@@bs.send] (** ES2015 *) + +external repeat : t -> int -> t = "repeat" [@@bs.send] (** ES2015 *) + +external replace : t -> old:t -> by:t -> t = "replace" [@@bs.send] + +external replaceRegex : t -> old:Js_re.t -> by:t -> t = "replace" [@@bs.send] + +external matchRegex : string -> Js_re.t -> t array option = "match" [@@bs.send] [@@bs.return {null_to_opt}] + +external split : t -> t -> t array = "split" [@@bs.send] + external splitAtMost: t -> t -> int -> t array = "split" [@@bs.send] +external startsWith : t -> t -> bool = "startsWith" [@@bs.send] + +external substr : t -> from:int -> len:int -> t = "substr" [@@bs.send] + +external substrToEnd : t -> from:int -> t = "substr" [@@bs.send] + +external slice : t -> from:int -> to_:int -> t = "slice" [@@bs.send] + +external sliceToEnd : t -> from:int -> t = "slice" [@@bs.send] + +external trim : t -> t = "trim" [@@bs.send] + +external trimStart : t -> t = "trimStart" [@@bs.send] (** ES2015 *) + +external trimEnd : t -> t = "trimEnd" [@@bs.send] (** ES2015 *) + +external padStart : t -> int -> t -> t = "padStart" [@@bs.send] (** ES2015 *) + +external padEnd : t -> int -> t -> t = "padEnd" [@@bs.send] (** ES2015 *) -(** ES2015: - [startsWith str substr] returns [true] if the [str] starts with [substr], [false] otherwise. - -@example {[ - startsWith "BuckleScript" "Buckle" = true;; - startsWith "BuckleScript" "" = true;; - startsWith "JavaScript" "Buckle" = false;; -]} -*) -external startsWith : t -> t -> bool = "" [@@bs.send] - - -(** - [substr ~from: n str] returns the substring of [str] from position [n] to the end of the string. - - If [n] is less than zero, the starting position is the length of [str] - [n]. - - If [n] is greater than or equal to the length of [str], returns the empty string. - -@example {[ - substr ~from: 3 "abcdefghij" = "defghij" - substr ~from: (-3) "abcdefghij" = "hij" - substr ~from: 12 "abcdefghij" = "" -]} -*) -external substr : from:int -> t = "" [@@bs.send.pipe: t] - - -(** - [trim str] returns a string that is [str] with whitespace stripped from both ends. Internal whitespace is not removed. - -@example {[ - trim " abc def " = "abc def" - trim "\n\r\t abc def \n\n\t\r " = "abc def" -]} -*) -external trim : t -> t = "" [@@bs.send] +external toLowerCase : t -> t = "toLowerCase" [@@bs.send] +external toUpperCase : t -> t = "toUpperCase" [@@bs.send] diff --git a/jscomp/others/belt_String.mli b/jscomp/others/belt_String.mli new file mode 100644 index 0000000000..145a1bed2a --- /dev/null +++ b/jscomp/others/belt_String.mli @@ -0,0 +1,326 @@ +(* Copyright (C) 2018 Authors of BuckleScript + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * In addition to the permissions granted to you by the LGPL, you may combine + * or link a "work that uses the Library" with a publicly distributed version + * of this file to produce a combined library or application, then distribute + * that combined work under the terms of your choosing, with no requirement + * to comply with the obligations normally placed on you by section 4 of the + * LGPL version 3 (or the corresponding section of a later version of the LGPL + * should you choose to use a later version). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) + +(** JavaScript String API *) + +type t = string + +(** [length str] returns the length of the string. + +@example {[ + length "abc" = 3;; +]} +*) +external length : t -> int = "length" [@@bs.get] + +(** [get str index] returns the string at [index]. + +@example {[ + get "abc" 1 = Some("b");; +]} +*) +external get : t -> int -> t option = "%array_unsafe_get" + +(** [concat append original] returns a new string with [append] added after [original]. + +@example {[ + concat "a" "b" = "ab";; +]} +*) +external concat : t -> t -> t = "concat" [@@bs.send] + +(** [concat arr original] returns a new string consisting of each item of an array of strings added to the [original] string. + +@example {[ + concatMany "1st" [|"2nd"; "3rd"; "4th"|] = "1st2nd3rd4th";; +]} +*) +external concatMany : t -> t array -> t = "concat" [@@bs.send] [@@bs.splice] + +(** ES2015: + [endsWith substr str] returns [true] if the [str] ends with [substr], [false] otherwise. + +@example {[ + endsWith "BuckleScript" "Script" = true;; + endsWith "BuckleShoes" "Script" = false;; +]} +*) +external endsWith : t -> t -> bool = "endsWith" [@@bs.send] + + +(** + [indexOf s searchValue ] returns an option containing the index of [searchValue] in [s] if found. + +@example {[ + indexOf "programmer" "gram" = Some(3);; + indexOf "programmer" "er" = Some(8);; + indexOf "programmer" "pro" = Some(0);; + indexOf "programmer" "xyz" = None;; +]} +*) +val indexOf: string -> string -> int option + +(** + [includes s searchValue ] returns [true] if [searchValue] is found anywhere within [s], [false] otherwise. + +@example {[ + includes "programmer" "gram" = true;; + includes "programmer" "er" = true;; + includes "programmer" "pro" = true;; + includes "programmer" "xyz" = false;; +]} +*) +external includes : t -> t -> bool = "includes" [@@bs.send] (** ES2015 *) + + + +(** + [repeat n s] returns a string that consists of [n] repetitions of [s]. Raises [RangeError] if [n] is negative. + +@example {[ + repeat "ha" 3 = "hahaha" + repeat "empty" 0 = "" +]} +*) +external repeat : t -> int -> t = "repeat" [@@bs.send] (** ES2015 *) + +(** [replace string substr newSubstr ] returns a new string which is +identical to [string] except with the first matching instance of [substr] +replaced by [newSubstr]. + +[substr] is treated as a verbatim string to match, not a regular +expression. + +@example {[ + replace "old string" ~old="old" ~by="new" = "new string" + replace "the cat and the dog" ~old="the" ~by="this" = "this cat and the dog" +]} +*) +external replace : t -> old:t -> by:t -> t = "replace" [@@bs.send] + +(** [replaceRegex string ~old=regex ~by=replacement] returns a new string where occurrences matching [regex] +have been replaced by [replacement]. + +@example {[ + replaceRegex ~old=[%re "/[aeiou]/g"] ~by="x" "vowels be gone" = "vxwxls bx gxnx" + replaceRegex ~old=[%re "/(\\w+) (\\w+)/"] ~by="$2, $1" "Juan Fulano" = "Fulano, Juan" +]} +*) +external replaceRegex : t -> old:Js_re.t -> by:t -> t = "replace" [@@bs.send] + + +(** + [matchRegex str regexp] matches a string against the given [regexp]. If there is no match, it returns [None]. + For regular expressions without the [g] modifier, if there is a match, the return value is [Some array] where the array contains: + + {ul + {- The entire matched string} + {- Any capture groups if the [regexp] had parentheses} + } + + For regular expressions with the [g] modifier, a matched expression returns [Some array] with all the matched substrings and no capture groups. + +@example {[ + matchRegex "The better bats" [%re "/b[aeiou]t/"] = Some [|"bet"|] + matchRegex "The better bats" [%re "/b[aeiou]t/g"] = Some [|"bet";"bat"|] + matchRegex "Today is 2018-04-05." [%re "/(\\d+)-(\\d+)-(\\d+)/"] = + Some [|"2018-04-05"; "2018"; "04"; "05"|] + matchRegex "The large container." [%re "/b[aeiou]g/"] = None +]} + +*) +external matchRegex : string -> Js_re.t -> t array option = "match" [@@bs.send] [@@bs.return {null_to_opt}] + +(** + [split delimiter str] splits the given [str] at every occurrence of [delimiter] and returns an + array of the resulting substrings. + +@example {[ + split "2018-01-02" "-" = [|"2018"; "01"; "02"|];; + split "a,b,,c" "," = [|"a"; "b"; ""; "c"|];; + split "good::bad as great::awful" "::" = [|"good"; "bad as great"; "awful"|];; + split "has-no-delimiter" ";" = [|"has-no-delimiter"|];; +]}; +*) +external split : t -> t -> t array = "split" [@@bs.send] + +(** + [splitAtMost str delimiter n] splits the given [str] at every occurrence of [delimiter] and + returns an array of the first [n] resulting substrings. If [n] is negative or greater than the + number of substrings, the array will contain all the substrings. + +@example {[ + splitAtMost "ant/bee/cat/dog/elk" "/" 3 = [|"ant"; "bee"; "cat"|];; + splitAtMost "ant/bee/cat/dog/elk" "/" 0 = [| |];; + splitAtMost "ant/bee/cat/dog/elk" "/" 9 = [|"ant"; "bee"; "cat"; "dog"; "elk"|];; +]} +*) +external splitAtMost: t -> t -> int -> t array = "split" [@@bs.send] + + +(** ES2015: + [startsWith str substr] returns [true] if the [str] starts with [substr], [false] otherwise. + +@example {[ + startsWith "BuckleScript" "Buckle" = true;; + startsWith "BuckleScript" "" = true;; + startsWith "JavaScript" "Buckle" = false;; +]} +*) +external startsWith : t -> t -> bool = "startsWith" [@@bs.send] + + +(** + [substr str ~from: n] returns the substring of [str] from position [n] to the end of the string. + + If [n] is less than zero, the starting position is the length of [str] - [n]. + + If [n] is greater than or equal to the length of [str], returns the empty string. + +@example {[ + substr "abcdefghij" ~from: 3 ~len: 2 = "de" + substr "abcdefghij" ~from: (-3) ~len: 3 = "hij" + substr "abcdefghij" ~from: 12 ~len: 2= "" +]} +*) +external substr : t -> from:int -> len:int -> t = "substr" [@@bs.send] + +(** + [substrToEnd str ~from: n] returns the substring of [str] from position [n] to the end of the string. + + If [n] is less than zero, the starting position is the length of [str] - [n]. + + If [n] is greater than or equal to the length of [str], returns the empty string. + +@example {[ + substrToEnd "abcdefghij" ~from: 3 = "defghij" + substrToEnd "abcdefghij" ~from: (-3) = "hij" + substrToEnd "abcdefghij" ~from: 12 = "" +]} +*) +external substrToEnd : t -> from:int -> t = "substr" [@@bs.send] + +(** [slice from:n1 to_:n2 str] returns the substring of [str] starting at character [n1] up to but not including [n2] + +If either [n1] or [n2] is negative, then it is evaluated as [length str - n1] (or [length str - n2]. + +If [n2] is greater than the length of [str], then it is treated as [length str]. + +If [n1] is greater than [n2], [slice] returns the empty string. + +@example {[ + slice "abcdefg" ~from:2 ~to_:5 == "cde";; + slice "abcdefg" ~from:2 ~to_:9 == "cdefg";; + slice "abcdefg" ~from:(-4) ~to_:(-2) == "de";; + slice "abcdefg" ~from:5 ~to_:1 == "";; +]} +*) +external slice : t -> from:int -> to_:int -> t = "slice" [@@bs.send] + +(** [sliceToEnd from: n str] returns the substring of [str] starting at character [n] to the end of the string + +If [n] is negative, then it is evaluated as [length str - n]. + +If [n] is greater than the length of [str], then [sliceToEnd] returns the empty string. + +@example {[ + sliceToEnd "abcdefg" ~from: 4 == "efg";; + sliceToEnd "abcdefg" ~from: (-2) == "fg";; + sliceToEnd "abcdefg" ~from: 7 == "";; +]} +*) +external sliceToEnd : t -> from:int -> t = "slice" [@@bs.send] + +(** + [trim str] returns a string that is [str] with whitespace stripped from both ends. Internal whitespace is not removed. + +@example {[ + trim " abc def " = "abc def" + trim "\n\r\t abc def \n\n\t\r " = "abc def" +]} +*) +external trim : t -> t = "trim" [@@bs.send] + +(** + [trimStart str] returns a string that is [str] with whitespace stripped from the start. Internal whitespace is not removed. + +@example {[ + trimStart " abc def " = "abc def " + trimStart "\n\r\t abc def \n\n\t\r " = "abc def \n\n\t\r" +]} +*) +external trimStart : t -> t = "trimStart" [@@bs.send] (** ES2015 *) + +(** + [trimEnd str] returns a string that is [str] with whitespace stripped from the end. Internal whitespace is not removed. + +@example {[ + trimEnd " abc def " = " abc def" + trimEnd "\n\r\t abc def \n\n\t\r " = "\n\r\t abc def" +]} +*) +external trimEnd : t -> t = "trimEnd" [@@bs.send] (** ES2015 *) + + +(** + [padStart str int padStr] returns a string that is [str] padded to the left with padStr. + +@example {[ + padStart "4" 3 "0" = "004" + padStart "444" 3 "0" = "444" +]} +*) +external padStart : t -> int -> t -> t = "padStart" [@@bs.send] (** ES2015 *) + +(** + [padEnd str int padStr] returns a string that is [str] padded to the right with padStr. + +@example {[ + padEnd "4" 3 "0" = "400" + padEnd "444" 3 "0" = "444" +]} +*) +external padEnd : t -> int -> t -> t = "padEnd" [@@bs.send] (** ES2015 *) + +(** + [toLowerCase str] converts [str] to lower case using the locale-insensitive case mappings in the Unicode Character Database. Notice that the conversion can give different results depending upon context, for example with the Greek letter sigma, which has two different lower case forms when it is the last character in a string or not. + +@example {[ + toLowerCase "ABC" = "abc";; + toLowerCase {js|ΣΠ|js} = {js|σπ|js};; + toLowerCase {js|ΠΣ|js} = {js|πς|js};; +]} +*) +external toLowerCase : t -> t = "toLowerCase" [@@bs.send] + +(** + [toUpperCase str] converts [str] to upper case using the locale-insensitive case mappings in the Unicode Character Database. Notice that the conversion can expand the number of letters in the result; for example the German [ß] capitalizes to two [S]es in a row. + +@example {[ + toUpperCase "abc" = "ABC";; + toUpperCase {js|Straße|js} = {js|STRASSE|js};; + toLowerCase {js|πς|js} = {js|ΠΣ|js};; +]} +*) +external toUpperCase : t -> t = "toUpperCase" [@@bs.send] diff --git a/jscomp/others/release.ninja b/jscomp/others/release.ninja index d93fea811a..af75ba31c4 100644 --- a/jscomp/others/release.ninja +++ b/jscomp/others/release.ninja @@ -118,6 +118,8 @@ build others/belt_SortArrayInt.cmj : cc others/belt_SortArrayInt.ml | others/bel build others/belt_SortArrayInt.cmi : cc others/belt_SortArrayInt.mli | runtime build others/belt_SortArrayString.cmj : cc others/belt_SortArrayString.ml | others/belt.cmi others/belt_Array.cmj others/belt_SortArrayString.cmi js_pkg runtime build others/belt_SortArrayString.cmi : cc others/belt_SortArrayString.mli | runtime +build others/belt_String.cmj : cc others/belt_String.ml | others/belt.cmi others/belt_String.cmi others/js_re.cmi js_pkg runtime +build others/belt_String.cmi : cc others/belt_String.mli | others/belt.cmi others/js_re.cmi js_pkg runtime build others/belt_internalAVLset.cmj : cc others/belt_internalAVLset.ml | others/belt.cmi others/belt_Array.cmj others/belt_Id.cmj others/belt_SortArray.cmj others/belt_internalAVLset.cmi js_pkg runtime build others/belt_internalAVLset.cmi : cc others/belt_internalAVLset.mli | others/belt.cmi others/belt_Id.cmi js_pkg runtime build others/belt_internalAVLtree.cmj : cc others/belt_internalAVLtree.ml | others/belt.cmi others/belt_Array.cmj others/belt_Id.cmj others/belt_SortArray.cmj others/belt_internalAVLtree.cmi js_pkg runtime @@ -142,4 +144,4 @@ build others/node_module.cmi others/node_module.cmj : cc others/node_module.ml | build others/node_path.cmi others/node_path.cmj : cc others/node_path.ml | runtime build others/node_process.cmj : cc others/node_process.ml | others/js_dict.cmj others/node.cmi others/node_process.cmi js_pkg runtime build others/node_process.cmi : cc others/node_process.mli | others/js_dict.cmi others/node.cmi js_pkg runtime -build others : phony others/belt_Array.cmi others/belt_Array.cmj others/belt_Debug.cmi others/belt_Debug.cmj others/belt_Float.cmi others/belt_Float.cmj others/belt_HashMap.cmi others/belt_HashMap.cmj others/belt_HashMapInt.cmi others/belt_HashMapInt.cmj others/belt_HashMapString.cmi others/belt_HashMapString.cmj others/belt_HashSet.cmi others/belt_HashSet.cmj others/belt_HashSetInt.cmi others/belt_HashSetInt.cmj others/belt_HashSetString.cmi others/belt_HashSetString.cmj others/belt_Id.cmi others/belt_Id.cmj others/belt_Int.cmi others/belt_Int.cmj others/belt_List.cmi others/belt_List.cmj others/belt_Map.cmi others/belt_Map.cmj others/belt_MapDict.cmi others/belt_MapDict.cmj others/belt_MapInt.cmi others/belt_MapInt.cmj others/belt_MapString.cmi others/belt_MapString.cmj others/belt_MutableMap.cmi others/belt_MutableMap.cmj others/belt_MutableMapInt.cmi others/belt_MutableMapInt.cmj others/belt_MutableMapString.cmi others/belt_MutableMapString.cmj others/belt_MutableQueue.cmi others/belt_MutableQueue.cmj others/belt_MutableSet.cmi others/belt_MutableSet.cmj others/belt_MutableSetInt.cmi others/belt_MutableSetInt.cmj others/belt_MutableSetString.cmi others/belt_MutableSetString.cmj others/belt_MutableStack.cmi others/belt_MutableStack.cmj others/belt_Option.cmi others/belt_Option.cmj others/belt_Range.cmi others/belt_Range.cmj others/belt_Result.cmi others/belt_Result.cmj others/belt_Set.cmi others/belt_Set.cmj others/belt_SetDict.cmi others/belt_SetDict.cmj others/belt_SetInt.cmi others/belt_SetInt.cmj others/belt_SetString.cmi others/belt_SetString.cmj others/belt_SortArray.cmi others/belt_SortArray.cmj others/belt_SortArrayInt.cmi others/belt_SortArrayInt.cmj others/belt_SortArrayString.cmi others/belt_SortArrayString.cmj others/belt_internalAVLset.cmi others/belt_internalAVLset.cmj others/belt_internalAVLtree.cmi others/belt_internalAVLtree.cmj others/belt_internalBuckets.cmi others/belt_internalBuckets.cmj others/belt_internalBucketsType.cmi others/belt_internalBucketsType.cmj others/belt_internalMapInt.cmi others/belt_internalMapInt.cmj others/belt_internalMapString.cmi others/belt_internalMapString.cmj others/belt_internalSetBuckets.cmi others/belt_internalSetBuckets.cmj others/belt_internalSetInt.cmi others/belt_internalSetInt.cmj others/belt_internalSetString.cmi others/belt_internalSetString.cmj others/dom.cmi others/dom_storage.cmi others/dom_storage2.cmi others/node_buffer.cmi others/node_buffer.cmj others/node_child_process.cmi others/node_child_process.cmj others/node_fs.cmi others/node_fs.cmj others/node_module.cmi others/node_module.cmj others/node_path.cmi others/node_path.cmj others/node_process.cmi others/node_process.cmj +build others : phony others/belt_Array.cmi others/belt_Array.cmj others/belt_Debug.cmi others/belt_Debug.cmj others/belt_Float.cmi others/belt_Float.cmj others/belt_HashMap.cmi others/belt_HashMap.cmj others/belt_HashMapInt.cmi others/belt_HashMapInt.cmj others/belt_HashMapString.cmi others/belt_HashMapString.cmj others/belt_HashSet.cmi others/belt_HashSet.cmj others/belt_HashSetInt.cmi others/belt_HashSetInt.cmj others/belt_HashSetString.cmi others/belt_HashSetString.cmj others/belt_Id.cmi others/belt_Id.cmj others/belt_Int.cmi others/belt_Int.cmj others/belt_List.cmi others/belt_List.cmj others/belt_Map.cmi others/belt_Map.cmj others/belt_MapDict.cmi others/belt_MapDict.cmj others/belt_MapInt.cmi others/belt_MapInt.cmj others/belt_MapString.cmi others/belt_MapString.cmj others/belt_MutableMap.cmi others/belt_MutableMap.cmj others/belt_MutableMapInt.cmi others/belt_MutableMapInt.cmj others/belt_MutableMapString.cmi others/belt_MutableMapString.cmj others/belt_MutableQueue.cmi others/belt_MutableQueue.cmj others/belt_MutableSet.cmi others/belt_MutableSet.cmj others/belt_MutableSetInt.cmi others/belt_MutableSetInt.cmj others/belt_MutableSetString.cmi others/belt_MutableSetString.cmj others/belt_MutableStack.cmi others/belt_MutableStack.cmj others/belt_Option.cmi others/belt_Option.cmj others/belt_Range.cmi others/belt_Range.cmj others/belt_Result.cmi others/belt_Result.cmj others/belt_Set.cmi others/belt_Set.cmj others/belt_SetDict.cmi others/belt_SetDict.cmj others/belt_SetInt.cmi others/belt_SetInt.cmj others/belt_SetString.cmi others/belt_SetString.cmj others/belt_SortArray.cmi others/belt_SortArray.cmj others/belt_SortArrayInt.cmi others/belt_SortArrayInt.cmj others/belt_SortArrayString.cmi others/belt_SortArrayString.cmj others/belt_String.cmi others/belt_String.cmj others/belt_internalAVLset.cmi others/belt_internalAVLset.cmj others/belt_internalAVLtree.cmi others/belt_internalAVLtree.cmj others/belt_internalBuckets.cmi others/belt_internalBuckets.cmj others/belt_internalBucketsType.cmi others/belt_internalBucketsType.cmj others/belt_internalMapInt.cmi others/belt_internalMapInt.cmj others/belt_internalMapString.cmi others/belt_internalMapString.cmj others/belt_internalSetBuckets.cmi others/belt_internalSetBuckets.cmj others/belt_internalSetInt.cmi others/belt_internalSetInt.cmj others/belt_internalSetString.cmi others/belt_internalSetString.cmj others/dom.cmi others/dom_storage.cmi others/dom_storage2.cmi others/node_buffer.cmi others/node_buffer.cmj others/node_child_process.cmi others/node_child_process.cmj others/node_fs.cmi others/node_fs.cmj others/node_module.cmi others/node_module.cmj others/node_path.cmi others/node_path.cmj others/node_process.cmi others/node_process.cmj diff --git a/jscomp/test/bs_string_test.js b/jscomp/test/bs_string_test.js index 022adcf6dc..257f40b079 100644 --- a/jscomp/test/bs_string_test.js +++ b/jscomp/test/bs_string_test.js @@ -2,6 +2,10 @@ var Mt = require("./mt.js"); var Block = require("../../lib/js/block.js"); +var Belt_Array = require("../../lib/js/belt_Array.js"); +var Belt_Option = require("../../lib/js/belt_Option.js"); +var Belt_String = require("../../lib/js/belt_String.js"); +var Caml_option = require("../../lib/js/caml_option.js"); var suites = /* record */[/* contents : [] */0]; @@ -28,9 +32,118 @@ eq("File \"bs_string_test.ml\", line 11, characters 5-12", "ghso ghso g".split(" return x + ("-" + y); }), ""), "-ghso-ghso-g"); -Mt.from_pair_suites("Bs_string_test", suites[0]); +eq("File \"bs_string_test.ml\", line 18, characters 5-12", "foo".length, 3); + +eq("File \"bs_string_test.ml\", line 19, characters 5-12", "".length, 0); + +eq("File \"bs_string_test.ml\", line 22, characters 5-12", "foo"[1], "o"); + +eq("File \"bs_string_test.ml\", line 23, characters 5-12", "foo"[5], undefined); + +eq("File \"bs_string_test.ml\", line 26, characters 5-12", "foo".concat("bar"), "foobar"); + +eq("File \"bs_string_test.ml\", line 29, characters 5-12", "foo".concat("bar", "baz"), "foobarbaz"); + +eq("File \"bs_string_test.ml\", line 30, characters 5-12", "".concat(), ""); + +eq("File \"bs_string_test.ml\", line 33, characters 5-12", "foo".endsWith("oo"), true); + +eq("File \"bs_string_test.ml\", line 34, characters 5-12", "foo".endsWith("a"), false); + +eq("File \"bs_string_test.ml\", line 37, characters 5-12", Belt_String.indexOf("foo", "oo"), 1); + +eq("File \"bs_string_test.ml\", line 38, characters 5-12", Belt_String.indexOf("foo", "a"), undefined); + +eq("File \"bs_string_test.ml\", line 41, characters 5-12", "foo".includes("oo"), true); + +eq("File \"bs_string_test.ml\", line 42, characters 5-12", "foo".includes("a"), false); + +eq("File \"bs_string_test.ml\", line 45, characters 5-12", "a".repeat(3), "aaa"); + +eq("File \"bs_string_test.ml\", line 46, characters 5-12", "a".repeat(0), ""); + +eq("File \"bs_string_test.ml\", line 49, characters 5-12", "hello world".replace("world", "you"), "hello you"); + +eq("File \"bs_string_test.ml\", line 50, characters 5-12", "hello world".replace("foo", "you"), "hello world"); + +eq("File \"bs_string_test.ml\", line 53, characters 5-12", "hello world".replace((/world/), "you"), "hello you"); + +eq("File \"bs_string_test.ml\", line 54, characters 5-12", "hello world world".replace((/world/g), "you"), "hello you you"); + +eq("File \"bs_string_test.ml\", line 55, characters 5-12", "hello world".replace((/foo/g), "you"), "hello world"); + +eq("File \"bs_string_test.ml\", line 59, characters 5-12", Caml_option.null_to_opt("hello world".match((/world/))) !== undefined, true); + +eq("File \"bs_string_test.ml\", line 60, characters 5-12", Belt_Option.map(Caml_option.null_to_opt("hello world".match((/world/))), (function (x) { + return x.length; + })), 1); + +eq("File \"bs_string_test.ml\", line 61, characters 5-12", Belt_Option.flatMap(Caml_option.null_to_opt("hello world".match((/world/))), (function (x) { + return Belt_Array.get(x, 0); + })), "world"); + +eq("File \"bs_string_test.ml\", line 62, characters 5-12", Caml_option.null_to_opt("hello world".match((/notfound/))), undefined); + +eq("File \"bs_string_test.ml\", line 65, characters 5-12", "hello world foo".split(" "), /* array */[ + "hello", + "world", + "foo" + ]); + +eq("File \"bs_string_test.ml\", line 68, characters 5-12", "hello world foo".split(" ", 1), /* array */["hello"]); + +eq("File \"bs_string_test.ml\", line 71, characters 5-12", "hello world".startsWith("hello"), true); + +eq("File \"bs_string_test.ml\", line 72, characters 5-12", "hello world".startsWith("world"), false); + +eq("File \"bs_string_test.ml\", line 75, characters 5-12", "hello world".substr(1, 3), "ell"); + +eq("File \"bs_string_test.ml\", line 78, characters 5-12", "hello world".substr(1), "ello world"); + +eq("File \"bs_string_test.ml\", line 79, characters 5-12", "hello world".substr(11), ""); + +eq("File \"bs_string_test.ml\", line 82, characters 5-12", "hello world".slice(1, 3), "el"); + +eq("File \"bs_string_test.ml\", line 83, characters 5-12", "hello world".slice(11, 12), ""); + +eq("File \"bs_string_test.ml\", line 86, characters 5-12", "hello world".slice(1), "ello world"); + +eq("File \"bs_string_test.ml\", line 87, characters 5-12", "hello world".slice(11), ""); + +eq("File \"bs_string_test.ml\", line 90, characters 5-12", " hello world ".trim(), "hello world"); + +eq("File \"bs_string_test.ml\", line 91, characters 5-12", "\n\r\t hello world\n\r\t ".trim(), "hello world"); + +eq("File \"bs_string_test.ml\", line 94, characters 5-12", " hello world ".trimStart(), "hello world "); + +eq("File \"bs_string_test.ml\", line 95, characters 5-12", "\n\r\t hello world\n\r\t ".trimStart(), "hello world\n\r\t "); + +eq("File \"bs_string_test.ml\", line 98, characters 5-12", " hello world ".trimEnd(), " hello world"); + +eq("File \"bs_string_test.ml\", line 99, characters 5-12", "\n\r\t hello world\n\r\t ".trimEnd(), "\n\r\t hello world"); + +eq("File \"bs_string_test.ml\", line 102, characters 5-12", "4".padStart(4, "x"), "xxx4"); + +eq("File \"bs_string_test.ml\", line 103, characters 5-12", "4444".padStart(4, "x"), "4444"); + +eq("File \"bs_string_test.ml\", line 104, characters 5-12", "4".padStart(4, "xy"), "xyx4"); + +eq("File \"bs_string_test.ml\", line 107, characters 5-12", "4".padEnd(4, "x"), "4xxx"); + +eq("File \"bs_string_test.ml\", line 108, characters 5-12", "4444".padEnd(4, "x"), "4444"); + +eq("File \"bs_string_test.ml\", line 109, characters 5-12", "4".padEnd(4, "xy"), "4xyx"); + +eq("File \"bs_string_test.ml\", line 112, characters 5-12", "HeLLo WorLd".toLowerCase(), "hello world"); + +eq("File \"bs_string_test.ml\", line 115, characters 5-12", "HeLLo WorLd".toUpperCase(), "HELLO WORLD"); + +Mt.from_pair_suites("bs_string_test.ml", suites[0]); + +var S = 0; exports.suites = suites; exports.test_id = test_id; exports.eq = eq; +exports.S = S; /* Not a pure module */ diff --git a/jscomp/test/bs_string_test.ml b/jscomp/test/bs_string_test.ml index a31910d936..9b46a5bd35 100644 --- a/jscomp/test/bs_string_test.ml +++ b/jscomp/test/bs_string_test.ml @@ -5,7 +5,7 @@ let eq loc x y = suites := (loc ^" id " ^ (string_of_int !test_id), (fun _ -> Mt.Eq(x,y))) :: !suites - +module S = Belt.String let () = eq __LOC__ @@ -14,6 +14,104 @@ let () = |. Js.Array2.reduce (fun x y -> x ^ "-" ^ y) "" ) "-ghso-ghso-g" +let () = + eq __LOC__ (S.length "foo") 3; + eq __LOC__ (S.length "") 0 + +let () = + eq __LOC__ (S.get "foo" 1) (Some "o"); + eq __LOC__ (S.get "foo" 5) None +let () = + eq __LOC__ (S.concat "foo" "bar") "foobar" + +let () = + eq __LOC__ (S.concatMany "foo" [|"bar"; "baz"|]) "foobarbaz"; + eq __LOC__ (S.concatMany "" [||]) "" + +let () = + eq __LOC__ (S.endsWith "foo" "oo") true; + eq __LOC__ (S.endsWith "foo" "a") false + +let () = + eq __LOC__ (S.indexOf "foo" "oo") (Some 1); + eq __LOC__ (S.indexOf "foo" "a") None + +let () = + eq __LOC__ (S.includes "foo" "oo") true; + eq __LOC__ (S.includes "foo" "a") false + +let () = + eq __LOC__ (S.repeat "a" 3) "aaa"; + eq __LOC__ (S.repeat "a" 0) "" + +let () = + eq __LOC__ (S.replace "hello world" ~old: "world" ~by: "you") "hello you"; + eq __LOC__ (S.replace "hello world" ~old: "foo" ~by: "you") "hello world" + +let () = + eq __LOC__ (S.replaceRegex "hello world" ~old: [%re "/world/"] ~by: "you") "hello you"; + eq __LOC__ (S.replaceRegex "hello world world" ~old: [%re "/world/g"] ~by: "you") "hello you you"; + eq __LOC__ (S.replaceRegex "hello world" ~old: [%re "/foo/g"] ~by: "you") "hello world" + +let () = + (* the following test is broken down because the deepEqual fails as JS adds properties to the array *) + eq __LOC__ (Belt.Option.isSome (S.matchRegex "hello world" [%re "/world/"])) true; + eq __LOC__ (Belt.Option.map (S.matchRegex "hello world" [%re "/world/"]) (fun x -> Belt.Array.length x)) (Some 1); + eq __LOC__ (Belt.Option.flatMap (S.matchRegex "hello world" [%re "/world/"]) (fun x -> Belt.Array.get x 0)) (Some "world"); + eq __LOC__ (S.matchRegex "hello world" [%re "/notfound/"]) None + +let () = + eq __LOC__ (S.split "hello world foo" " ") [|"hello"; "world"; "foo"|] + +let () = + eq __LOC__ (S.splitAtMost "hello world foo" " " 1) [|"hello"|] + +let () = + eq __LOC__ (S.startsWith "hello world" "hello") true; + eq __LOC__ (S.startsWith "hello world" "world") false + +let () = + eq __LOC__ (S.substr "hello world" ~from: 1 ~len: 3) "ell" + +let () = + eq __LOC__ (S.substrToEnd "hello world" ~from: 1) "ello world"; + eq __LOC__ (S.substrToEnd "hello world" ~from: 11) "" + +let () = + eq __LOC__ (S.slice "hello world" ~from: 1 ~to_: 3) "el"; + eq __LOC__ (S.slice "hello world" ~from: 11 ~to_: 12) "" + +let () = + eq __LOC__ (S.sliceToEnd "hello world" ~from: 1) "ello world"; + eq __LOC__ (S.sliceToEnd "hello world" ~from: 11) "" + +let () = + eq __LOC__ (S.trim " hello world ") "hello world"; + eq __LOC__ (S.trim "\n\r\t hello world\n\r\t ") "hello world" + +let () = + eq __LOC__ (S.trimStart " hello world ") "hello world "; + eq __LOC__ (S.trimStart "\n\r\t hello world\n\r\t ") "hello world\n\r\t " + +let () = + eq __LOC__ (S.trimEnd " hello world ") " hello world"; + eq __LOC__ (S.trimEnd "\n\r\t hello world\n\r\t ") "\n\r\t hello world" + +let () = + eq __LOC__ (S.padStart "4" 4 "x") "xxx4"; + eq __LOC__ (S.padStart "4444" 4 "x") "4444"; + eq __LOC__ (S.padStart "4" 4 "xy") "xyx4" + +let () = + eq __LOC__ (S.padEnd "4" 4 "x") "4xxx"; + eq __LOC__ (S.padEnd "4444" 4 "x") "4444"; + eq __LOC__ (S.padEnd "4" 4 "xy") "4xyx" + +let () = + eq __LOC__ (S.toLowerCase "HeLLo WorLd") "hello world" + +let () = + eq __LOC__ (S.toUpperCase "HeLLo WorLd") "HELLO WORLD" -let () = Mt.from_pair_suites __MODULE__ !suites \ No newline at end of file +let () = Mt.from_pair_suites __FILE__ !suites diff --git a/lib/js/belt.js b/lib/js/belt.js index 5bfd498848..feccdc04f0 100644 --- a/lib/js/belt.js +++ b/lib/js/belt.js @@ -35,6 +35,8 @@ var Int = 0; var Float = 0; +var $$String = 0; + var Debug = 0; exports.Id = Id; @@ -54,5 +56,6 @@ exports.$$Option = $$Option; exports.Result = Result; exports.Int = Int; exports.Float = Float; +exports.$$String = $$String; exports.Debug = Debug; /* No side effect */ diff --git a/lib/js/belt_String.js b/lib/js/belt_String.js index ae1b9f17e6..aca6c50e8b 100644 --- a/lib/js/belt_String.js +++ b/lib/js/belt_String.js @@ -1 +1,13 @@ -/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ +'use strict'; + + +function indexOf(s, searchValue) { + var value = s.indexOf(searchValue); + if (value !== -1) { + return value; + } + +} + +exports.indexOf = indexOf; +/* No side effect */ From e298dc21f13fc2d75fb12aedbb28268a9575c20f Mon Sep 17 00:00:00 2001 From: Matthias Le Brun Date: Tue, 2 Apr 2019 13:34:54 +0200 Subject: [PATCH 3/3] Use bs.variadic for concatMany so that array doesn't have to be syntactic --- jscomp/others/belt_String.ml | 2 +- jscomp/test/bs_string_test.js | 93 +++++++++++++++++++---------------- jscomp/test/bs_string_test.ml | 2 + 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/jscomp/others/belt_String.ml b/jscomp/others/belt_String.ml index ea6e7bc8d2..c0a18da67c 100644 --- a/jscomp/others/belt_String.ml +++ b/jscomp/others/belt_String.ml @@ -32,7 +32,7 @@ external get : t -> int -> t option = "%array_unsafe_get" external concat : t -> t -> t = "concat" [@@bs.send] -external concatMany : t -> t array -> t = "concat" [@@bs.send] [@@bs.splice] +external concatMany : t -> t array -> t = "concat" [@@bs.send] [@@bs.variadic] external endsWith : t -> t -> bool = "endsWith" [@@bs.send] diff --git a/jscomp/test/bs_string_test.js b/jscomp/test/bs_string_test.js index 257f40b079..a6d7c35f4b 100644 --- a/jscomp/test/bs_string_test.js +++ b/jscomp/test/bs_string_test.js @@ -44,99 +44,106 @@ eq("File \"bs_string_test.ml\", line 26, characters 5-12", "foo".concat("bar"), eq("File \"bs_string_test.ml\", line 29, characters 5-12", "foo".concat("bar", "baz"), "foobarbaz"); -eq("File \"bs_string_test.ml\", line 30, characters 5-12", "".concat(), ""); +var array = /* array */[ + "bar", + "baz" +]; -eq("File \"bs_string_test.ml\", line 33, characters 5-12", "foo".endsWith("oo"), true); +eq("File \"bs_string_test.ml\", line 31, characters 7-14", Block.spliceObjApply("foo", "concat", [array]), "foobarbaz"); -eq("File \"bs_string_test.ml\", line 34, characters 5-12", "foo".endsWith("a"), false); +eq("File \"bs_string_test.ml\", line 32, characters 5-12", "".concat(), ""); -eq("File \"bs_string_test.ml\", line 37, characters 5-12", Belt_String.indexOf("foo", "oo"), 1); +eq("File \"bs_string_test.ml\", line 35, characters 5-12", "foo".endsWith("oo"), true); -eq("File \"bs_string_test.ml\", line 38, characters 5-12", Belt_String.indexOf("foo", "a"), undefined); +eq("File \"bs_string_test.ml\", line 36, characters 5-12", "foo".endsWith("a"), false); -eq("File \"bs_string_test.ml\", line 41, characters 5-12", "foo".includes("oo"), true); +eq("File \"bs_string_test.ml\", line 39, characters 5-12", Belt_String.indexOf("foo", "oo"), 1); -eq("File \"bs_string_test.ml\", line 42, characters 5-12", "foo".includes("a"), false); +eq("File \"bs_string_test.ml\", line 40, characters 5-12", Belt_String.indexOf("foo", "a"), undefined); -eq("File \"bs_string_test.ml\", line 45, characters 5-12", "a".repeat(3), "aaa"); +eq("File \"bs_string_test.ml\", line 43, characters 5-12", "foo".includes("oo"), true); -eq("File \"bs_string_test.ml\", line 46, characters 5-12", "a".repeat(0), ""); +eq("File \"bs_string_test.ml\", line 44, characters 5-12", "foo".includes("a"), false); -eq("File \"bs_string_test.ml\", line 49, characters 5-12", "hello world".replace("world", "you"), "hello you"); +eq("File \"bs_string_test.ml\", line 47, characters 5-12", "a".repeat(3), "aaa"); -eq("File \"bs_string_test.ml\", line 50, characters 5-12", "hello world".replace("foo", "you"), "hello world"); +eq("File \"bs_string_test.ml\", line 48, characters 5-12", "a".repeat(0), ""); -eq("File \"bs_string_test.ml\", line 53, characters 5-12", "hello world".replace((/world/), "you"), "hello you"); +eq("File \"bs_string_test.ml\", line 51, characters 5-12", "hello world".replace("world", "you"), "hello you"); -eq("File \"bs_string_test.ml\", line 54, characters 5-12", "hello world world".replace((/world/g), "you"), "hello you you"); +eq("File \"bs_string_test.ml\", line 52, characters 5-12", "hello world".replace("foo", "you"), "hello world"); -eq("File \"bs_string_test.ml\", line 55, characters 5-12", "hello world".replace((/foo/g), "you"), "hello world"); +eq("File \"bs_string_test.ml\", line 55, characters 5-12", "hello world".replace((/world/), "you"), "hello you"); -eq("File \"bs_string_test.ml\", line 59, characters 5-12", Caml_option.null_to_opt("hello world".match((/world/))) !== undefined, true); +eq("File \"bs_string_test.ml\", line 56, characters 5-12", "hello world world".replace((/world/g), "you"), "hello you you"); -eq("File \"bs_string_test.ml\", line 60, characters 5-12", Belt_Option.map(Caml_option.null_to_opt("hello world".match((/world/))), (function (x) { +eq("File \"bs_string_test.ml\", line 57, characters 5-12", "hello world".replace((/foo/g), "you"), "hello world"); + +eq("File \"bs_string_test.ml\", line 61, characters 5-12", Caml_option.null_to_opt("hello world".match((/world/))) !== undefined, true); + +eq("File \"bs_string_test.ml\", line 62, characters 5-12", Belt_Option.map(Caml_option.null_to_opt("hello world".match((/world/))), (function (x) { return x.length; })), 1); -eq("File \"bs_string_test.ml\", line 61, characters 5-12", Belt_Option.flatMap(Caml_option.null_to_opt("hello world".match((/world/))), (function (x) { +eq("File \"bs_string_test.ml\", line 63, characters 5-12", Belt_Option.flatMap(Caml_option.null_to_opt("hello world".match((/world/))), (function (x) { return Belt_Array.get(x, 0); })), "world"); -eq("File \"bs_string_test.ml\", line 62, characters 5-12", Caml_option.null_to_opt("hello world".match((/notfound/))), undefined); +eq("File \"bs_string_test.ml\", line 64, characters 5-12", Caml_option.null_to_opt("hello world".match((/notfound/))), undefined); -eq("File \"bs_string_test.ml\", line 65, characters 5-12", "hello world foo".split(" "), /* array */[ +eq("File \"bs_string_test.ml\", line 67, characters 5-12", "hello world foo".split(" "), /* array */[ "hello", "world", "foo" ]); -eq("File \"bs_string_test.ml\", line 68, characters 5-12", "hello world foo".split(" ", 1), /* array */["hello"]); +eq("File \"bs_string_test.ml\", line 70, characters 5-12", "hello world foo".split(" ", 1), /* array */["hello"]); -eq("File \"bs_string_test.ml\", line 71, characters 5-12", "hello world".startsWith("hello"), true); +eq("File \"bs_string_test.ml\", line 73, characters 5-12", "hello world".startsWith("hello"), true); -eq("File \"bs_string_test.ml\", line 72, characters 5-12", "hello world".startsWith("world"), false); +eq("File \"bs_string_test.ml\", line 74, characters 5-12", "hello world".startsWith("world"), false); -eq("File \"bs_string_test.ml\", line 75, characters 5-12", "hello world".substr(1, 3), "ell"); +eq("File \"bs_string_test.ml\", line 77, characters 5-12", "hello world".substr(1, 3), "ell"); -eq("File \"bs_string_test.ml\", line 78, characters 5-12", "hello world".substr(1), "ello world"); +eq("File \"bs_string_test.ml\", line 80, characters 5-12", "hello world".substr(1), "ello world"); -eq("File \"bs_string_test.ml\", line 79, characters 5-12", "hello world".substr(11), ""); +eq("File \"bs_string_test.ml\", line 81, characters 5-12", "hello world".substr(11), ""); -eq("File \"bs_string_test.ml\", line 82, characters 5-12", "hello world".slice(1, 3), "el"); +eq("File \"bs_string_test.ml\", line 84, characters 5-12", "hello world".slice(1, 3), "el"); -eq("File \"bs_string_test.ml\", line 83, characters 5-12", "hello world".slice(11, 12), ""); +eq("File \"bs_string_test.ml\", line 85, characters 5-12", "hello world".slice(11, 12), ""); -eq("File \"bs_string_test.ml\", line 86, characters 5-12", "hello world".slice(1), "ello world"); +eq("File \"bs_string_test.ml\", line 88, characters 5-12", "hello world".slice(1), "ello world"); -eq("File \"bs_string_test.ml\", line 87, characters 5-12", "hello world".slice(11), ""); +eq("File \"bs_string_test.ml\", line 89, characters 5-12", "hello world".slice(11), ""); -eq("File \"bs_string_test.ml\", line 90, characters 5-12", " hello world ".trim(), "hello world"); +eq("File \"bs_string_test.ml\", line 92, characters 5-12", " hello world ".trim(), "hello world"); -eq("File \"bs_string_test.ml\", line 91, characters 5-12", "\n\r\t hello world\n\r\t ".trim(), "hello world"); +eq("File \"bs_string_test.ml\", line 93, characters 5-12", "\n\r\t hello world\n\r\t ".trim(), "hello world"); -eq("File \"bs_string_test.ml\", line 94, characters 5-12", " hello world ".trimStart(), "hello world "); +eq("File \"bs_string_test.ml\", line 96, characters 5-12", " hello world ".trimStart(), "hello world "); -eq("File \"bs_string_test.ml\", line 95, characters 5-12", "\n\r\t hello world\n\r\t ".trimStart(), "hello world\n\r\t "); +eq("File \"bs_string_test.ml\", line 97, characters 5-12", "\n\r\t hello world\n\r\t ".trimStart(), "hello world\n\r\t "); -eq("File \"bs_string_test.ml\", line 98, characters 5-12", " hello world ".trimEnd(), " hello world"); +eq("File \"bs_string_test.ml\", line 100, characters 5-12", " hello world ".trimEnd(), " hello world"); -eq("File \"bs_string_test.ml\", line 99, characters 5-12", "\n\r\t hello world\n\r\t ".trimEnd(), "\n\r\t hello world"); +eq("File \"bs_string_test.ml\", line 101, characters 5-12", "\n\r\t hello world\n\r\t ".trimEnd(), "\n\r\t hello world"); -eq("File \"bs_string_test.ml\", line 102, characters 5-12", "4".padStart(4, "x"), "xxx4"); +eq("File \"bs_string_test.ml\", line 104, characters 5-12", "4".padStart(4, "x"), "xxx4"); -eq("File \"bs_string_test.ml\", line 103, characters 5-12", "4444".padStart(4, "x"), "4444"); +eq("File \"bs_string_test.ml\", line 105, characters 5-12", "4444".padStart(4, "x"), "4444"); -eq("File \"bs_string_test.ml\", line 104, characters 5-12", "4".padStart(4, "xy"), "xyx4"); +eq("File \"bs_string_test.ml\", line 106, characters 5-12", "4".padStart(4, "xy"), "xyx4"); -eq("File \"bs_string_test.ml\", line 107, characters 5-12", "4".padEnd(4, "x"), "4xxx"); +eq("File \"bs_string_test.ml\", line 109, characters 5-12", "4".padEnd(4, "x"), "4xxx"); -eq("File \"bs_string_test.ml\", line 108, characters 5-12", "4444".padEnd(4, "x"), "4444"); +eq("File \"bs_string_test.ml\", line 110, characters 5-12", "4444".padEnd(4, "x"), "4444"); -eq("File \"bs_string_test.ml\", line 109, characters 5-12", "4".padEnd(4, "xy"), "4xyx"); +eq("File \"bs_string_test.ml\", line 111, characters 5-12", "4".padEnd(4, "xy"), "4xyx"); -eq("File \"bs_string_test.ml\", line 112, characters 5-12", "HeLLo WorLd".toLowerCase(), "hello world"); +eq("File \"bs_string_test.ml\", line 114, characters 5-12", "HeLLo WorLd".toLowerCase(), "hello world"); -eq("File \"bs_string_test.ml\", line 115, characters 5-12", "HeLLo WorLd".toUpperCase(), "HELLO WORLD"); +eq("File \"bs_string_test.ml\", line 117, characters 5-12", "HeLLo WorLd".toUpperCase(), "HELLO WORLD"); Mt.from_pair_suites("bs_string_test.ml", suites[0]); diff --git a/jscomp/test/bs_string_test.ml b/jscomp/test/bs_string_test.ml index 9b46a5bd35..8ef1ef14c6 100644 --- a/jscomp/test/bs_string_test.ml +++ b/jscomp/test/bs_string_test.ml @@ -27,6 +27,8 @@ let () = let () = eq __LOC__ (S.concatMany "foo" [|"bar"; "baz"|]) "foobarbaz"; + let array = [|"bar"; "baz"|] in + eq __LOC__ (S.concatMany "foo" array) "foobarbaz"; eq __LOC__ (S.concatMany "" [||]) "" let () =