123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657(********************************************************************************)(* crs - A tool for managing inline review comments embedded in source code *)(* Copyright (C) 2024-2026 Mathieu Barbin <mathieu.barbin@gmail.com> *)(* *)(* This file is part of crs. *)(* *)(* crs 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 any later version, *)(* with the LGPL-3.0 Linking Exception. *)(* *)(* crs 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 and *)(* the file `NOTICE.md` at the root of this repository for more details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* and the LGPL-3.0 Linking Exception along with this library. If not, see *)(* <http://www.gnu.org/licenses/> and <https://spdx.org>, respectively. *)(********************************************************************************)typet=stringletcompare=String.compareletequal=String.equalletto_stringt=tletto_dyn=Dyn.stringletis_valid_char=function|'0'..'9'|'a'..'z'|'A'..'Z'|'-'|'_'|'.'|'['|']'->true|_->false;;letinvariantt=(not(String.is_emptyt))&&String.for_allt~f:is_valid_charletof_stringstr=ifinvariantstrthenOkstrelseError(`Msg(Printf.sprintf"%S: invalid user_handle"str));;letvstr=matchof_stringstrwith|Okt->t|Error(`Msgmsg)->invalid_argmsg;;letto_jsont:Json.t=`String(to_stringt)letof_jsonjson=match(json:Json.t)with|`Stringstr->(matchof_stringstrwith|Okt->t|Error(`Msgmsg)->raise(Json.Error(json,msg)))|_->raise(Json.Error(json,"User handle expected to be a json string."));;