diff --git a/jscomp/others/js_re.ml b/jscomp/others/js_re.ml index 8eea4f8093..f161961ba0 100644 --- a/jscomp/others/js_re.ml +++ b/jscomp/others/js_re.ml @@ -23,169 +23,162 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) (** - Provides bindings for JavaScript Regular Expressions - - {4 Syntax sugar} - ReScript provides a bit of syntax sugar for regex literals: `[%re "/foo/g"]` - will evaluate to a [` t`]() that can be passed around and used like usual. + Provide bindings to JS regular expressions (RegExp). **Note:** This is not an immutable API. A RegExp object with the `global` ("g") - flag set will modify the [` lastIndex`]() property when the RegExp object is used, - and subsequent uses will ocntinue the search from the previous [` lastIndex`](). - - ``` - let maybeMatches = "banana" |> Js.String.match_ [%re "/na+/g"] - ``` - - **see** [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) - - **see** [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) + flag set will modify the [`lastIndex`]() property when the RegExp object is used, + and subsequent uses will continue the search from the previous [`lastIndex`](). *) -(** the RegExp object *) +(** The RegExp object. *) type t -(** the result of a executing a RegExp on a string *) +(** The result of a executing a RegExp on a string. *) type result -(** an array of the match and captures, the first is the full match and the remaining are the substring captures *) +(** + An `array` of the match and captures, the first is the full match and the + remaining are the substring captures. +*) external captures : result -> string Js.nullable array = "%identity" (** - an array of the matches, the first is the full match and the remaining are the substring matches + Deprecated. Use `captures` instead. *) external matches : result -> string array = "%identity" [@@deprecated "Use Js.Re.captures instead"] -(** 0-based index of the match in the input string *) +(** 0-based index of the match in the input string. *) external index : result -> int = "index" [@@bs.get] -(** the original input string *) +(** The original input string. *) external input : result -> string = "input" [@@bs.get] (** - Constructs a RegExp object ([` t`]()) from a string - - Regex literals (`[%re "/.../"]`) should generally be preferred, but - `fromString` is very useful when you need to insert a string into a regex. - - ``` - (* A function that extracts the content of the first element with the given tag *) - - let contentOf tag xmlString = - Js.Re.fromString ("<" ^ tag ^ ">(.*?)<\/" ^ tag ^">") - |> Js.Re.exec xmlString - |> function - | Some result -> Js.Nullable.toOption (Js.Re.captures result).(1) - | None -> None + Constructs a RegExp object (Js.Re.t) from a `string`. + Regex literals `%re("/.../")` should generally be preferred, but `fromString` + is useful when you need to dynamically construct a regex using strings, + exactly like when you do so in JavaScript. + + ```res example + let firstReScriptFileExtension = (filename, content) => { + let result = Js.Re.fromString(filename ++ "\.(res|resi)")->Js.Re.exec_(content) + switch result { + | Some(r) => Js.Nullable.toOption(Js.Re.captures(r)[1]) + | None => None + } + } + + // outputs "res" + firstReScriptFileExtension("School", "School.res School.resi Main.js School.bs.js") ``` *) external fromString : string -> t = "RegExp" [@@bs.new] (** - Constructs a RegExp object ([` t`]()) from a string with the given `flags` - - See [` fromString`]() + Constructs a RegExp object (`Js.Re.t`) from a string with the given flags. + See `Js.Re.fromString`. Valid flags: - - g: global - - i: ignore case - - m: multiline - - u: unicode (es2015) - - y: sticky (es2015) + - **g** global + - **i** ignore case + - **m** multiline + - **u** unicode (es2015) + - **y** sticky (es2015) *) external fromStringWithFlags : string -> flags:string -> t = "RegExp" [@@bs.new] -(** returns the enabled flags as a string *) +(** Returns the enabled flags as a string. *) external flags : t -> string = "flags" [@@bs.get] -(** returns a bool indicating whether the `global` flag is set *) +(** Returns a `bool` indicating whether the global flag is set. *) external global : t -> bool = "global" [@@bs.get] -(** returns a bool indicating whether the `ignoreCase` flag is set *) +(** Returns a `bool` indicating whether the ignoreCase flag is set. *) external ignoreCase : t -> bool = "ignoreCase" [@@bs.get] (** - returns the index where the next match will start its search - - This property will be modified when the RegExp object is used, if the `global` ("g") - flag is set. - - ``` - (* Finds and prints successive matches *) - - let re = [%re "/ab*/g"] in - let str = "abbcdefabh" in - - let break = ref false in - while not !break do - match re |> Js.Re.exec str with - | None -> break := true - | Some result -> - Js.Nullable.iter (Js.Re.captures result).(0) ((fun match_ -> - let next = string_of_int (Js.Re.lastIndex re) in - Js.log ("Found " ^ match_ ^ ". Next match starts at " ^ next))) - done + Returns the index where the next match will start its search. This property + will be modified when the RegExp object is used, if the global ("g") flag is + set. + + ```res example + let re = %re("/ab*/g") + let str = "abbcdefabh" + + let break = ref(false) + while !break.contents { + switch Js.Re.exec_(re, str) { + | Some(result) => Js.Nullable.iter(Js.Re.captures(result)[0], (. match_) => { + let next = Belt.Int.toString(Js.Re.lastIndex(re)) + Js.log("Found " ++ (match_ ++ (". Next match starts at " ++ next))) + }) + | None => break := true + } + } ``` - **see** [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex) + See + [`RegExp: lastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex) + on MDN. *) external lastIndex : t -> int = "lastIndex" [@@bs.get] -(** sets the index at which the next match will start its search from *) +(** Sets the index at which the next match will start its search from. *) external setLastIndex : t -> int -> unit = "lastIndex" [@@bs.set] -(** returns a bool indicating whether the `multiline` flag is set *) +(** Returns a `bool` indicating whether the multiline flag is set. *) external multiline : t -> bool = "multiline" [@@bs.get] -(** returns the pattern as a string *) +(** Returns the pattern as a `string`. *) external source : t -> string = "source" [@@bs.get] -(** returns a bool indicating whether the `sticky` flag is set *) +(** Returns a `bool` indicating whether the sticky flag is set. *) external sticky : t -> bool = "sticky" [@@bs.get] -(** returns a bool indicating whether the `unicode` flag is set *) +(** Returns a `bool` indicating whether the unicode flag is set. *) external unicode : t -> bool = "unicode" [@@bs.get] (** - executes a search on a given string using the given RegExp object + Executes a search on a given string using the given RegExp object. + Returns `Some(Js.Re.result)` if a match is found, `None` otherwise. - **return** `Some` [` result`]() if a match is found, `None` otherwise - - ``` - (* Match "quick brown" followed by "jumps", ignoring characters in between + ```res example + /* Match "quick brown" followed by "jumps", ignoring characters in between * Remember "brown" and "jumps" * Ignore case - *) + */ - let re = [%re "/quick\s(brown).+?(jumps)/ig"] in - let result = re |. Js.Re.exec_ "The Quick Brown Fox Jumps Over The Lazy Dog" + let re = %re("/quick\s(brown).+?(jumps)/ig") + let result = Js.Re.exec_(re, "The Quick Brown Fox Jumps Over The Lazy Dog") ``` - **see** [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec) + See + [`RegExp.prototype.exec()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec) + on MDN. *) external exec_ : t -> string -> result option = "exec" [@@bs.send] [@@bs.return null_to_opt] (** - tests whether the given RegExp object will match a given string + Tests whether the given RegExp object will match a given `string`. + Returns true if a match is found, false otherwise. - **return** `true` if a match is found, `false` otherwise - - ``` - (* A simple implementation of Js.String.startsWith *) + ```res example + /* A simple implementation of Js.String.startsWith */ let str = "hello world!" - let startsWith target substring = - Js.Re.fromString ("^" ^ substring) - |. Js.Re.test_ target + let startsWith = (target, substring) => + Js.Re.fromString("^" ++ substring)->Js.Re.test_(target) - let () = Js.log (str |. startsWith "hello") (* prints "true" *) + Js.log(str->startsWith("hello")) /* prints "true" */ ``` - **see** [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test) + See + [`RegExp.prototype.test()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test) + on MDN. *) external test_ : t -> string -> bool = "test" [@@bs.send]