package transom
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
OCaml backend/application logic for desktop WebView apps
Install
dune-project
Dependency
Authors
Maintainers
Sources
v0.2.0.tar.gz
md5=4d0b0117994a250dd343bbc03f65acf5
sha512=629a5e39f3b142ff0391bbcab6a193480d07d04b3a101da85693778dae6539f48b48bc5c36cf24ed4a920da26bab2b9c955d2bb2a5c43fc3dcaec137523a7527
doc/src/transom.codegen/manifest.ml.html
Source file manifest.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305type command_name = string type ocaml_module = string type ocaml_type = string type ts_type = string type typescript_module = string type command = { name : command_name; request : ocaml_type; response : ocaml_type; event : ocaml_type option; ts_request : ts_type; ts_response : ts_type; ts_event : ts_type option; } type t = { service_module : ocaml_module; types_module : ocaml_module; json_module : ocaml_module; typescript_types_module : typescript_module; commands : command list; } let command_name_to_string value = value let ocaml_module_to_string value = value let ocaml_type_to_string value = value let ts_type_to_string value = value let typescript_module_to_string value = value let error message = Error message let assoc path = function | `Assoc fields -> Ok fields | _ -> error (path ^ " must be an object") let field path name fields = match List.assoc_opt name fields with | Some value -> Ok value | None -> error (path ^ "." ^ name ^ " is required") let non_empty_string path = function | `String value when String.length value > 0 -> Ok value | `String _ -> error (path ^ " must be non-empty") | _ -> error (path ^ " must be a string") let is_lower_start = function 'a' .. 'z' | '_' -> true | _ -> false let is_upper_start = function 'A' .. 'Z' -> true | _ -> false let is_identifier_start = function | 'a' .. 'z' | 'A' .. 'Z' | '_' -> true | _ -> false let is_identifier_char = function | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' -> true | _ -> false let words text = String.split_on_char ' ' text let ocaml_keywords = words (String.concat " " [ "and as assert begin class constraint do done downto else end"; "exception external false for fun function functor if in include"; "inherit initializer lazy let match method module mutable new nonrec"; "object of open or private rec sig struct then to true try type"; "val virtual when while with"; ]) let ts_keywords = words (String.concat " " [ "as async await break case catch class const continue debugger"; "default delete do else enum export extends false finally for from"; "function if import in instanceof let new null of return super switch"; "this throw true try type typeof var void while with"; ]) let valid_identifier ~start value = String.length value > 0 && value <> "_" && start value.[0] && String.for_all is_identifier_char value let valid_ocaml_value_name value = valid_identifier ~start:is_lower_start value && not (List.mem value ocaml_keywords) let valid_ocaml_type_name = valid_ocaml_value_name let valid_ts_identifier value = valid_identifier ~start:is_identifier_start value && not (List.mem value ts_keywords) let valid_command_name value = valid_ocaml_value_name value && valid_ts_identifier value let valid_ocaml_module_name value = valid_identifier ~start:is_upper_start value let valid_ocaml_module_path value = match String.split_on_char '.' value with | [] -> false | segments -> List.for_all valid_ocaml_module_name segments let validate_name path expected valid value = if valid value then Ok () else error (path ^ " must be " ^ expected) let string_field path name fields = match field path name fields with | Error message -> error message | Ok value -> non_empty_string (path ^ "." ^ name) value let optional_string_field path name fields = match List.assoc_opt name fields with | None -> Ok None | Some value -> ( match non_empty_string (path ^ "." ^ name) value with | Ok value -> Ok (Some value) | Error message -> error message) let validate_optional path expected valid = function | None -> Ok () | Some value -> validate_name path expected valid value let generated_helper_names = [ "bad_request"; "dispatch"; "run_stdio" ] let validate_command_helper_name path command = if List.mem command.name generated_helper_names then error (path ^ ".name collides with generated helper: " ^ command.name) else Ok () let validate_command path command = match ( validate_name (path ^ ".name") "a lowercase OCaml/TypeScript identifier" valid_command_name command.name, validate_command_helper_name path command, validate_name (path ^ ".request") "an OCaml type identifier" valid_ocaml_type_name command.request, validate_name (path ^ ".response") "an OCaml type identifier" valid_ocaml_type_name command.response, validate_optional (path ^ ".event") "an OCaml type identifier" valid_ocaml_type_name command.event, validate_name (path ^ ".ts_request") "a TypeScript type identifier" valid_ts_identifier command.ts_request, validate_name (path ^ ".ts_response") "a TypeScript type identifier" valid_ts_identifier command.ts_response, validate_optional (path ^ ".ts_event") "a TypeScript type identifier" valid_ts_identifier command.ts_event ) with | Ok (), Ok (), Ok (), Ok (), Ok (), Ok (), Ok (), Ok () -> Ok command | Error message, _, _, _, _, _, _, _ | _, Error message, _, _, _, _, _, _ | _, _, Error message, _, _, _, _, _ | _, _, _, Error message, _, _, _, _ | _, _, _, _, Error message, _, _, _ | _, _, _, _, _, Error message, _, _ | _, _, _, _, _, _, Error message, _ | _, _, _, _, _, _, _, Error message -> error message let command_of_yojson index json = let path = Printf.sprintf "commands[%d]" index in match assoc path json with | Error message -> error message | Ok fields -> ( let required name = string_field path name fields in let optional name = optional_string_field path name fields in match ( required "name", required "request", required "response", optional "event", optional "ts_request", required "ts_response", optional "ts_event" ) with | ( Ok name, Ok request, Ok response, Ok event, Ok ts_request, Ok ts_response, Ok ts_event ) -> let command = { name; request; response; event; ts_request = Option.value ts_request ~default:request; ts_response; ts_event = (match ts_event with Some _ -> ts_event | None -> event); } in validate_command path command | Error message, _, _, _, _, _, _ | _, Error message, _, _, _, _, _ | _, _, Error message, _, _, _, _ | _, _, _, Error message, _, _, _ | _, _, _, _, Error message, _, _ | _, _, _, _, _, Error message, _ | _, _, _, _, _, _, Error message -> error message) module Names = Set.Make (String) let check_unique_names commands = let rec loop seen = function | [] -> Ok () | command :: rest -> if Names.mem command.name seen then error ("duplicate command name: " ^ command.name) else loop (Names.add command.name seen) rest in loop Names.empty commands let commands_of_yojson = function | `List commands -> let rec loop index acc = function | [] -> ( let commands = List.rev acc in match check_unique_names commands with | Ok () -> Ok commands | Error message -> error message) | json :: rest -> ( match command_of_yojson index json with | Ok command -> loop (index + 1) (command :: acc) rest | Error message -> error message) in loop 0 [] commands | _ -> error "commands must be an array" let of_yojson json = match assoc "manifest" json with | Error message -> error message | Ok fields -> ( let required name = string_field "manifest" name fields in let typescript_types_module = match optional_string_field "manifest" "typescript_types_module" fields with | Ok (Some value) -> Ok value | Ok None -> Ok "./api_types" | Error message -> error message in match ( required "service_module", required "types_module", required "json_module", typescript_types_module, field "manifest" "commands" fields ) with | ( Ok service_module, Ok types_module, Ok json_module, Ok typescript_types_module, Ok commands_json ) -> ( match commands_of_yojson commands_json with | Ok commands -> ( match ( validate_name "manifest.service_module" "an OCaml module path" valid_ocaml_module_path service_module, validate_name "manifest.types_module" "an OCaml module path" valid_ocaml_module_path types_module, validate_name "manifest.json_module" "an OCaml module path" valid_ocaml_module_path json_module ) with | Ok (), Ok (), Ok () -> Ok { service_module; types_module; json_module; typescript_types_module; commands; } | Error message, _, _ | _, Error message, _ | _, _, Error message -> error message) | Error message -> error message) | Error message, _, _, _, _ | _, Error message, _, _, _ | _, _, Error message, _, _ | _, _, _, Error message, _ | _, _, _, _, Error message -> error message) let read_file path = let input = open_in_bin path in Fun.protect ~finally:(fun () -> close_in_noerr input) (fun () -> let length = in_channel_length input in really_input_string input length) let load_file path = match read_file path with | exception Sys_error message -> error message | text -> ( match Yojson.Safe.from_string text with | json -> of_yojson json | exception Yojson.Json_error message -> error ("invalid JSON: " ^ message) )
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>