├── .gitignore ├── .merlin ├── .tern-project ├── Makefile ├── README.markdown ├── _oasis ├── _tags ├── configure ├── examples ├── Makefile ├── buffer_example.ml ├── dns_example.ml ├── events_example.ml ├── example.json ├── file_system.ml ├── high_level.ml ├── net_example.ml └── os_example.ml ├── examples_lwt ├── Makefile └── file_system.ml ├── myocamlbuild.ml ├── opam ├── descr ├── findlib └── opam ├── setup.ml └── src ├── META ├── higher_level ├── high_level.mldylib ├── high_level.mllib ├── higher_level.mldylib ├── higher_level.mllib └── nodejs_high_level.ml ├── higher_level_lwt ├── high_level_lwt.mldylib ├── high_level_lwt.mllib └── nodejs_high_level_lwt.ml ├── nodejs.ml ├── nodejs.mldylib └── nodejs.mllib /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | *.byte 3 | *.docdir 4 | 5 | tests/*.cmi 6 | tests/*.cmo 7 | tests/*.cmt 8 | tests/*.out 9 | 10 | examples/*.cmi 11 | examples/*.cmo 12 | examples/*.cmt 13 | examples/*.out 14 | 15 | setup.data 16 | setup.log 17 | notes.txt 18 | scratch.js 19 | server.js 20 | exhaust_api.js 21 | .tern-port 22 | chat_server.js 23 | examples/node_modules 24 | package.json 25 | junk.ml 26 | *.js 27 | 28 | examples/buffer 29 | examples/file_system 30 | examples_lwt 31 | old_readme 32 | node_modules -------------------------------------------------------------------------------- /.merlin: -------------------------------------------------------------------------------- 1 | S src 2 | B _build/src 3 | PKG js_of_ocaml js_of_ocaml.ppx nodejs nodejs.high_level nodejs.high_level_lwt 4 | FLG -w +a-4-40..42-44-45-48 5 | -------------------------------------------------------------------------------- /.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "node": { 4 | } 5 | } 6 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: a3c674b4239234cbbe53afe090018954) 3 | 4 | SETUP = ocaml setup.ml 5 | 6 | build: setup.data 7 | $(SETUP) -build $(BUILDFLAGS) 8 | 9 | doc: setup.data build 10 | $(SETUP) -doc $(DOCFLAGS) 11 | 12 | test: setup.data build 13 | $(SETUP) -test $(TESTFLAGS) 14 | 15 | all: 16 | $(SETUP) -all $(ALLFLAGS) 17 | 18 | install: setup.data 19 | $(SETUP) -install $(INSTALLFLAGS) 20 | 21 | uninstall: setup.data 22 | $(SETUP) -uninstall $(UNINSTALLFLAGS) 23 | 24 | reinstall: setup.data 25 | $(SETUP) -reinstall $(REINSTALLFLAGS) 26 | 27 | clean: 28 | $(SETUP) -clean $(CLEANFLAGS) 29 | 30 | distclean: 31 | $(SETUP) -distclean $(DISTCLEANFLAGS) 32 | 33 | setup.data: 34 | $(SETUP) -configure $(CONFIGUREFLAGS) 35 | 36 | configure: 37 | $(SETUP) -configure $(CONFIGUREFLAGS) 38 | 39 | .PHONY: build doc test all install uninstall reinstall clean distclean configure 40 | 41 | # OASIS_STOP 42 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | OCaml on nodejs 2 | ================= 3 | 4 | These are OCaml bindings to Nodejs. I'm currently rewriting everything 5 | from a previous iteration and so things might get outdated quickly. 6 | 7 | 8 | Included are three levels of abstraction, 9 | 10 | 1. `Nodejs` 11 | 2. `Nodejs_high_level` 12 | 3. `Nodejs_high_level_lwt` 13 | 14 | they correspond to the findlib packages: 15 | 16 | ``` 17 | nodejs 18 | nodejs.high_level 19 | nodejs.high_level_lwt 20 | ``` 21 | 22 | You will probably be using this library at the 2/3 level. 23 | 24 | High level Nodejs API Examples 25 | ================================== 26 | 27 | All can be compiled and run with these steps: 28 | 29 | ```shell 30 | $ ocamlfind ocamlc -g -package nodejs.high_level_lwt -linkpkg code.ml 31 | $ js_of_ocaml --debug-info --no-inline --pretty a.out -o T.js 32 | $ node T.js 33 | ``` 34 | 35 | Using Lwt: 36 | 37 | ```ocaml 38 | open Lwt.Infix 39 | 40 | let () = 41 | (Nodejs_high_level_lwt.Fs.read_file (Nodejs_high_level.__filename ()) 42 | >>= fun (err, result) -> result#to_string |> print_endline |> Lwt.return 43 | >|= fun () -> print_endline "Finished Program and Ordered Async") 44 | |> Lwt.ignore_result 45 | ``` 46 | 47 | Plain server: 48 | 49 | ```ocaml 50 | open Nodejs_high_level 51 | 52 | let () = 53 | let s = 54 | new Net.server (fun client -> 55 | client#write "Welcome to the Matrix"; 56 | print_endline "Client connected") 57 | in 58 | 59 | s#listen 8124 (fun () -> print_endline "Created a server") 60 | ``` 61 | -------------------------------------------------------------------------------- /_oasis: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | OASISFormat: 0.4 3 | Name: nodejs 4 | Version: 1.0.0 5 | Synopsis: js_of_ocaml bindings for nodejs 6 | Authors: Edgar Aroutiounian 7 | Maintainers: Edgar Aroutiounian 8 | Homepage: https://github.com/fxfactorial/ocaml-nodejs 9 | License: BSD-3-clause 10 | Plugins: META (0.4), DevFiles (0.4) 11 | BuildTools: ocamlbuild 12 | 13 | Description: 14 | Write OCaml, run on node 15 | 16 | These are js_of_ocaml bindings to the node JavaScript API. 17 | Get all the power of the node ecosystem with the type safety 18 | of OCaml. 19 | 20 | Library nodejs 21 | Path: src 22 | Modules: Nodejs 23 | CompiledObject: byte 24 | ByteOpt: -g -w +a-4-40..42-44-45-48 25 | BuildDepends: 26 | js_of_ocaml (>= 2.8.1), 27 | js_of_ocaml.ppx, 28 | lwt.ppx, 29 | lwt (>= 2.5.2) 30 | 31 | Library high_level 32 | FindlibName: high_level 33 | FindlibParent: nodejs 34 | Path: src/higher_level 35 | Modules: Nodejs_high_level 36 | CompiledObject: byte 37 | ByteOpt: -g -w +a-4-40..42-44-45-48 38 | BuildDepends: nodejs 39 | 40 | Library high_level_lwt 41 | FindlibName: high_level_lwt 42 | FindlibParent: nodejs 43 | Path: src/higher_level_lwt 44 | Modules: Nodejs_high_level_lwt 45 | CompiledObject: byte 46 | ByteOpt: -g -w +a-4-40..42-44-45-48 47 | BuildDepends: nodejs.high_level 48 | 49 | SourceRepository master 50 | Type: git 51 | Location: https://github.com/fxfactorial/ocaml-nodejs.git 52 | Browser: https://github.com/fxfactorial/ocaml-nodejs -------------------------------------------------------------------------------- /_tags: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 489249b49b97e38712418115aed3c29e) 3 | # Ignore VCS directories, you can use the same kind of rule outside 4 | # OASIS_START/STOP if you want to exclude directories that contains 5 | # useless stuff for the build process 6 | true: annot, bin_annot 7 | <**/.svn>: -traverse 8 | <**/.svn>: not_hygienic 9 | ".bzr": -traverse 10 | ".bzr": not_hygienic 11 | ".hg": -traverse 12 | ".hg": not_hygienic 13 | ".git": -traverse 14 | ".git": not_hygienic 15 | "_darcs": -traverse 16 | "_darcs": not_hygienic 17 | # Library nodejs 18 | "src/nodejs.cmxs": use_nodejs 19 | "src/nodejs.cma": oasis_library_nodejs_byte 20 | : oasis_library_nodejs_byte 21 | : pkg_js_of_ocaml 22 | : pkg_js_of_ocaml.ppx 23 | : pkg_lwt 24 | : pkg_lwt.ppx 25 | # Library high_level 26 | "src/higher_level/high_level.cmxs": use_high_level 27 | "src/higher_level/high_level.cma": oasis_library_high_level_byte 28 | : oasis_library_high_level_byte 29 | : pkg_js_of_ocaml 30 | : pkg_js_of_ocaml.ppx 31 | : pkg_lwt 32 | : pkg_lwt.ppx 33 | : use_nodejs 34 | # Library high_level_lwt 35 | "src/higher_level_lwt/high_level_lwt.cmxs": use_high_level_lwt 36 | "src/higher_level_lwt/high_level_lwt.cma": oasis_library_high_level_lwt_byte 37 | : oasis_library_high_level_lwt_byte 38 | : pkg_js_of_ocaml 39 | : pkg_js_of_ocaml.ppx 40 | : pkg_lwt 41 | : pkg_lwt.ppx 42 | : use_high_level 43 | : use_nodejs 44 | # OASIS_STOP 45 | "examples": not_hygienic 46 | "examples_lwt": not_hygienic 47 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # OASIS_START 4 | # DO NOT EDIT (digest: dc86c2ad450f91ca10c931b6045d0499) 5 | set -e 6 | 7 | FST=true 8 | for i in "$@"; do 9 | if $FST; then 10 | set -- 11 | FST=false 12 | fi 13 | 14 | case $i in 15 | --*=*) 16 | ARG=${i%%=*} 17 | VAL=${i##*=} 18 | set -- "$@" "$ARG" "$VAL" 19 | ;; 20 | *) 21 | set -- "$@" "$i" 22 | ;; 23 | esac 24 | done 25 | 26 | ocaml setup.ml -configure "$@" 27 | # OASIS_STOP 28 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | pkgs := nodejs.high_level,js_of_ocaml.ppx 2 | js_debug := --debug-info --no-inline --pretty 3 | 4 | all:buffer file_system high_level events dns net os_high_level 5 | 6 | buffer:buffer_example.ml 7 | ocamlfind ocamlc -g -package ${pkgs} -linkpkg $< -o $@ 8 | js_of_ocaml ${js_debug} $@ -o $@.js 9 | node $@.js 10 | 11 | file_system:file_system.ml 12 | ocamlfind ocamlc -g -package ${pkgs} -linkpkg $< -o $@ 13 | js_of_ocaml ${js_debug} $@ -o $@.js 14 | node $@.js 15 | 16 | high_level:high_level.ml 17 | ocamlfind ocamlc -g -package ${pkgs} -linkpkg $< -o $@ 18 | js_of_ocaml ${js_debug} $@ -o $@.js 19 | node $@.js 20 | 21 | events:events_example.ml 22 | ocamlfind ocamlc -g -package ${pkgs} -linkpkg $< -o $@ 23 | js_of_ocaml ${js_debug} $@ -o $@.js 24 | node $@.js 25 | 26 | dns:dns_example.ml 27 | ocamlfind ocamlc -g -package ${pkgs} -linkpkg $< -o $@ 28 | js_of_ocaml ${js_debug} $@ -o $@.js 29 | node $@.js 30 | 31 | net:net_example.ml 32 | ocamlfind ocamlc -g -package ${pkgs} -linkpkg $< -o $@ 33 | js_of_ocaml ${js_debug} $@ -o $@.js 34 | node $@.js 35 | 36 | os_high_level:os_example.ml 37 | ocamlfind ocamlc -g -package ${pkgs} -linkpkg $< -o $@ 38 | js_of_ocaml ${js_debug} $@ -o $@.js 39 | node $@.js 40 | 41 | clean: 42 | @rm -f *.cmi *.cmo *.cmt a.out *.js \ 43 | buffer file_system high_level events \ 44 | dns net os_high_level 45 | 46 | .PHONY:clean file_system buffer dns events net os_high_level 47 | -------------------------------------------------------------------------------- /examples/buffer_example.ml: -------------------------------------------------------------------------------- 1 | 2 | let () = 3 | let item = Nodejs.Buffer.buffer_static##from (Js.string "Hello World") in 4 | Printf.sprintf "Length: %d" item##.length |> print_endline 5 | -------------------------------------------------------------------------------- /examples/dns_example.ml: -------------------------------------------------------------------------------- 1 | 2 | (* let () = *) 3 | (* Nodejs.Dns.dns##resolve4 *) 4 | (* (Js.string "google.com") *) 5 | (* (Js.wrap_callback *) 6 | (* (fun arr -> *) 7 | (* Firebug.console##log arr; *) 8 | (* arr *) 9 | (* |> Js.str_array |> Js.to_array *) 10 | (* |> Array.map Js.to_string |> Array.to_list *) 11 | (* |> List.iter print_endline)) *) 12 | 13 | -------------------------------------------------------------------------------- /examples/events_example.ml: -------------------------------------------------------------------------------- 1 | 2 | 3 | let () = 4 | let e = new%js Nodejs.Events.event_emitter in 5 | 6 | e##addListener 7 | (Js.string "eventOne") 8 | (Js.wrap_callback (fun () -> print_endline "Called in the event callback")); 9 | 10 | let b = 11 | (* Add this to jsoo api itself *) 12 | e##eventNames |> Js.str_array |> Js.to_array 13 | |> Array.map Js.to_string |> Array.to_list 14 | in 15 | 16 | List.iter print_endline b; 17 | 18 | e##emit (Js.string "eventOne") 19 | -------------------------------------------------------------------------------- /examples/example.json: -------------------------------------------------------------------------------- 1 | [{"first": "item"}, 2 | {"second": "thing"}] 3 | -------------------------------------------------------------------------------- /examples/file_system.ml: -------------------------------------------------------------------------------- 1 | let () = 2 | let result = 3 | Nodejs.Fs.fs##readFileSync 4 | (Js.string "example.json") 5 | (object%js 6 | val encoding = Js.null 7 | val flag = Js.string "r" 8 | end) 9 | in 10 | result##toString |> Js.to_string |> print_endline 11 | 12 | let () = 13 | Nodejs.Fs.fs##readFile 14 | (Js.string "example.json") 15 | (Js.wrap_callback (fun _ contents -> 16 | contents##toString |> Js.to_string |> print_endline 17 | )) 18 | -------------------------------------------------------------------------------- /examples/high_level.ml: -------------------------------------------------------------------------------- 1 | open Nodejs_high_level 2 | 3 | let () = 4 | Fs.read_file_sync "example.json" Fs.Read |> print_endline; 5 | 6 | Fs.read_file_async "example.json" 7 | (fun err contents -> contents#to_string |> print_endline) 8 | 9 | let () = 10 | let e = new Events.event_emmiter in 11 | e#add_listener "speak" (fun _ -> print_endline "Called on speak event"); 12 | e#event_names |> List.iter print_endline; 13 | e#emit "speak" 14 | 15 | let () = 16 | let s = 17 | new Net.server (fun client -> 18 | client#write "Welcome to the Matrix"; 19 | print_endline "Client connected") 20 | in 21 | 22 | s#listen 8124 (fun () -> print_endline "Created a server") 23 | -------------------------------------------------------------------------------- /examples/net_example.ml: -------------------------------------------------------------------------------- 1 | 2 | open Nodejs 3 | 4 | let () = 5 | let server = Net.net##createServer_withConnListener 6 | (Js.wrap_callback (fun c -> 7 | 8 | print_endline "Client connected"; 9 | 10 | c##on_withNoArgs 11 | (Js.string "end") 12 | (Js.wrap_callback (fun () -> print_endline "Client disconnected")); 13 | 14 | 15 | c##write (Buffer.buffer_static##from (Js.string "Hello\r\n")); 16 | 17 | c##pipe c |> ignore; 18 | 19 | ())) 20 | in 21 | server##listen 8124 (Js.wrap_callback (fun _ -> print_endline "Server bound")) 22 | -------------------------------------------------------------------------------- /examples/os_example.ml: -------------------------------------------------------------------------------- 1 | 2 | let () = 3 | Nodejs_high_level.Os.cpu_stats () 4 | |> List.iter (fun cpu -> 5 | let open Nodejs_high_level.Os in 6 | Printf.sprintf "model %s, speed: %d, times: idle: %d, sys: %d, user: %d" 7 | cpu.model cpu.speed cpu.times#idle cpu.times#idle cpu.times#user 8 | |> print_endline) 9 | -------------------------------------------------------------------------------- /examples_lwt/Makefile: -------------------------------------------------------------------------------- 1 | pkgs := nodejs.high_level_lwt 2 | js_debug := --debug-info --no-inline --pretty 3 | 4 | file_system:file_system.ml 5 | ocamlfind ocamlc -g -package ${pkgs} -linkpkg $< -o $@ 6 | js_of_ocaml ${js_debug} $@ -o $@.js 7 | node $@.js 8 | 9 | clean: 10 | @rm -f *.cmi *.cmo *.cmt a.out *.js \ 11 | file_system 12 | 13 | 14 | .PHONY:clean file_system 15 | -------------------------------------------------------------------------------- /examples_lwt/file_system.ml: -------------------------------------------------------------------------------- 1 | open Lwt.Infix 2 | 3 | let () = 4 | (Nodejs_high_level_lwt.Fs.read_file (Nodejs_high_level.__filename ()) 5 | >>= fun (err, result) -> result#to_string |> print_endline |> Lwt.return 6 | >|= fun () -> print_endline "Finished Program and Ordered Async") 7 | |> Lwt.ignore_result 8 | 9 | -------------------------------------------------------------------------------- /myocamlbuild.ml: -------------------------------------------------------------------------------- 1 | (* OASIS_START *) 2 | (* DO NOT EDIT (digest: d27d68596339d1cde6f19123586c3ac2) *) 3 | module OASISGettext = struct 4 | (* # 22 "src/oasis/OASISGettext.ml" *) 5 | 6 | 7 | let ns_ str = 8 | str 9 | 10 | 11 | let s_ str = 12 | str 13 | 14 | 15 | let f_ (str: ('a, 'b, 'c, 'd) format4) = 16 | str 17 | 18 | 19 | let fn_ fmt1 fmt2 n = 20 | if n = 1 then 21 | fmt1^^"" 22 | else 23 | fmt2^^"" 24 | 25 | 26 | let init = 27 | [] 28 | 29 | 30 | end 31 | 32 | module OASISString = struct 33 | (* # 22 "src/oasis/OASISString.ml" *) 34 | 35 | 36 | (** Various string utilities. 37 | 38 | Mostly inspired by extlib and batteries ExtString and BatString libraries. 39 | 40 | @author Sylvain Le Gall 41 | *) 42 | 43 | 44 | let nsplitf str f = 45 | if str = "" then 46 | [] 47 | else 48 | let buf = Buffer.create 13 in 49 | let lst = ref [] in 50 | let push () = 51 | lst := Buffer.contents buf :: !lst; 52 | Buffer.clear buf 53 | in 54 | let str_len = String.length str in 55 | for i = 0 to str_len - 1 do 56 | if f str.[i] then 57 | push () 58 | else 59 | Buffer.add_char buf str.[i] 60 | done; 61 | push (); 62 | List.rev !lst 63 | 64 | 65 | (** [nsplit c s] Split the string [s] at char [c]. It doesn't include the 66 | separator. 67 | *) 68 | let nsplit str c = 69 | nsplitf str ((=) c) 70 | 71 | 72 | let find ~what ?(offset=0) str = 73 | let what_idx = ref 0 in 74 | let str_idx = ref offset in 75 | while !str_idx < String.length str && 76 | !what_idx < String.length what do 77 | if str.[!str_idx] = what.[!what_idx] then 78 | incr what_idx 79 | else 80 | what_idx := 0; 81 | incr str_idx 82 | done; 83 | if !what_idx <> String.length what then 84 | raise Not_found 85 | else 86 | !str_idx - !what_idx 87 | 88 | 89 | let sub_start str len = 90 | let str_len = String.length str in 91 | if len >= str_len then 92 | "" 93 | else 94 | String.sub str len (str_len - len) 95 | 96 | 97 | let sub_end ?(offset=0) str len = 98 | let str_len = String.length str in 99 | if len >= str_len then 100 | "" 101 | else 102 | String.sub str 0 (str_len - len) 103 | 104 | 105 | let starts_with ~what ?(offset=0) str = 106 | let what_idx = ref 0 in 107 | let str_idx = ref offset in 108 | let ok = ref true in 109 | while !ok && 110 | !str_idx < String.length str && 111 | !what_idx < String.length what do 112 | if str.[!str_idx] = what.[!what_idx] then 113 | incr what_idx 114 | else 115 | ok := false; 116 | incr str_idx 117 | done; 118 | if !what_idx = String.length what then 119 | true 120 | else 121 | false 122 | 123 | 124 | let strip_starts_with ~what str = 125 | if starts_with ~what str then 126 | sub_start str (String.length what) 127 | else 128 | raise Not_found 129 | 130 | 131 | let ends_with ~what ?(offset=0) str = 132 | let what_idx = ref ((String.length what) - 1) in 133 | let str_idx = ref ((String.length str) - 1) in 134 | let ok = ref true in 135 | while !ok && 136 | offset <= !str_idx && 137 | 0 <= !what_idx do 138 | if str.[!str_idx] = what.[!what_idx] then 139 | decr what_idx 140 | else 141 | ok := false; 142 | decr str_idx 143 | done; 144 | if !what_idx = -1 then 145 | true 146 | else 147 | false 148 | 149 | 150 | let strip_ends_with ~what str = 151 | if ends_with ~what str then 152 | sub_end str (String.length what) 153 | else 154 | raise Not_found 155 | 156 | 157 | let replace_chars f s = 158 | let buf = Buffer.create (String.length s) in 159 | String.iter (fun c -> Buffer.add_char buf (f c)) s; 160 | Buffer.contents buf 161 | 162 | let lowercase_ascii = 163 | replace_chars 164 | (fun c -> 165 | if (c >= 'A' && c <= 'Z') then 166 | Char.chr (Char.code c + 32) 167 | else 168 | c) 169 | 170 | let uncapitalize_ascii s = 171 | if s <> "" then 172 | (lowercase_ascii (String.sub s 0 1)) ^ (String.sub s 1 ((String.length s) - 1)) 173 | else 174 | s 175 | 176 | let uppercase_ascii = 177 | replace_chars 178 | (fun c -> 179 | if (c >= 'a' && c <= 'z') then 180 | Char.chr (Char.code c - 32) 181 | else 182 | c) 183 | 184 | let capitalize_ascii s = 185 | if s <> "" then 186 | (uppercase_ascii (String.sub s 0 1)) ^ (String.sub s 1 ((String.length s) - 1)) 187 | else 188 | s 189 | 190 | end 191 | 192 | module OASISExpr = struct 193 | (* # 22 "src/oasis/OASISExpr.ml" *) 194 | 195 | 196 | 197 | 198 | 199 | open OASISGettext 200 | 201 | 202 | type test = string 203 | 204 | 205 | type flag = string 206 | 207 | 208 | type t = 209 | | EBool of bool 210 | | ENot of t 211 | | EAnd of t * t 212 | | EOr of t * t 213 | | EFlag of flag 214 | | ETest of test * string 215 | 216 | 217 | 218 | type 'a choices = (t * 'a) list 219 | 220 | 221 | let eval var_get t = 222 | let rec eval' = 223 | function 224 | | EBool b -> 225 | b 226 | 227 | | ENot e -> 228 | not (eval' e) 229 | 230 | | EAnd (e1, e2) -> 231 | (eval' e1) && (eval' e2) 232 | 233 | | EOr (e1, e2) -> 234 | (eval' e1) || (eval' e2) 235 | 236 | | EFlag nm -> 237 | let v = 238 | var_get nm 239 | in 240 | assert(v = "true" || v = "false"); 241 | (v = "true") 242 | 243 | | ETest (nm, vl) -> 244 | let v = 245 | var_get nm 246 | in 247 | (v = vl) 248 | in 249 | eval' t 250 | 251 | 252 | let choose ?printer ?name var_get lst = 253 | let rec choose_aux = 254 | function 255 | | (cond, vl) :: tl -> 256 | if eval var_get cond then 257 | vl 258 | else 259 | choose_aux tl 260 | | [] -> 261 | let str_lst = 262 | if lst = [] then 263 | s_ "" 264 | else 265 | String.concat 266 | (s_ ", ") 267 | (List.map 268 | (fun (cond, vl) -> 269 | match printer with 270 | | Some p -> p vl 271 | | None -> s_ "") 272 | lst) 273 | in 274 | match name with 275 | | Some nm -> 276 | failwith 277 | (Printf.sprintf 278 | (f_ "No result for the choice list '%s': %s") 279 | nm str_lst) 280 | | None -> 281 | failwith 282 | (Printf.sprintf 283 | (f_ "No result for a choice list: %s") 284 | str_lst) 285 | in 286 | choose_aux (List.rev lst) 287 | 288 | 289 | end 290 | 291 | 292 | # 292 "myocamlbuild.ml" 293 | module BaseEnvLight = struct 294 | (* # 22 "src/base/BaseEnvLight.ml" *) 295 | 296 | 297 | module MapString = Map.Make(String) 298 | 299 | 300 | type t = string MapString.t 301 | 302 | 303 | let default_filename = 304 | Filename.concat 305 | (Sys.getcwd ()) 306 | "setup.data" 307 | 308 | 309 | let load ?(allow_empty=false) ?(filename=default_filename) () = 310 | if Sys.file_exists filename then 311 | begin 312 | let chn = 313 | open_in_bin filename 314 | in 315 | let st = 316 | Stream.of_channel chn 317 | in 318 | let line = 319 | ref 1 320 | in 321 | let st_line = 322 | Stream.from 323 | (fun _ -> 324 | try 325 | match Stream.next st with 326 | | '\n' -> incr line; Some '\n' 327 | | c -> Some c 328 | with Stream.Failure -> None) 329 | in 330 | let lexer = 331 | Genlex.make_lexer ["="] st_line 332 | in 333 | let rec read_file mp = 334 | match Stream.npeek 3 lexer with 335 | | [Genlex.Ident nm; Genlex.Kwd "="; Genlex.String value] -> 336 | Stream.junk lexer; 337 | Stream.junk lexer; 338 | Stream.junk lexer; 339 | read_file (MapString.add nm value mp) 340 | | [] -> 341 | mp 342 | | _ -> 343 | failwith 344 | (Printf.sprintf 345 | "Malformed data file '%s' line %d" 346 | filename !line) 347 | in 348 | let mp = 349 | read_file MapString.empty 350 | in 351 | close_in chn; 352 | mp 353 | end 354 | else if allow_empty then 355 | begin 356 | MapString.empty 357 | end 358 | else 359 | begin 360 | failwith 361 | (Printf.sprintf 362 | "Unable to load environment, the file '%s' doesn't exist." 363 | filename) 364 | end 365 | 366 | 367 | let rec var_expand str env = 368 | let buff = 369 | Buffer.create ((String.length str) * 2) 370 | in 371 | Buffer.add_substitute 372 | buff 373 | (fun var -> 374 | try 375 | var_expand (MapString.find var env) env 376 | with Not_found -> 377 | failwith 378 | (Printf.sprintf 379 | "No variable %s defined when trying to expand %S." 380 | var 381 | str)) 382 | str; 383 | Buffer.contents buff 384 | 385 | 386 | let var_get name env = 387 | var_expand (MapString.find name env) env 388 | 389 | 390 | let var_choose lst env = 391 | OASISExpr.choose 392 | (fun nm -> var_get nm env) 393 | lst 394 | end 395 | 396 | 397 | # 397 "myocamlbuild.ml" 398 | module MyOCamlbuildFindlib = struct 399 | (* # 22 "src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml" *) 400 | 401 | 402 | (** OCamlbuild extension, copied from 403 | * http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild 404 | * by N. Pouillard and others 405 | * 406 | * Updated on 2009/02/28 407 | * 408 | * Modified by Sylvain Le Gall 409 | *) 410 | open Ocamlbuild_plugin 411 | 412 | type conf = 413 | { no_automatic_syntax: bool; 414 | } 415 | 416 | (* these functions are not really officially exported *) 417 | let run_and_read = 418 | Ocamlbuild_pack.My_unix.run_and_read 419 | 420 | 421 | let blank_sep_strings = 422 | Ocamlbuild_pack.Lexers.blank_sep_strings 423 | 424 | 425 | let exec_from_conf exec = 426 | let exec = 427 | let env_filename = Pathname.basename BaseEnvLight.default_filename in 428 | let env = BaseEnvLight.load ~filename:env_filename ~allow_empty:true () in 429 | try 430 | BaseEnvLight.var_get exec env 431 | with Not_found -> 432 | Printf.eprintf "W: Cannot get variable %s\n" exec; 433 | exec 434 | in 435 | let fix_win32 str = 436 | if Sys.os_type = "Win32" then begin 437 | let buff = Buffer.create (String.length str) in 438 | (* Adapt for windowsi, ocamlbuild + win32 has a hard time to handle '\\'. 439 | *) 440 | String.iter 441 | (fun c -> Buffer.add_char buff (if c = '\\' then '/' else c)) 442 | str; 443 | Buffer.contents buff 444 | end else begin 445 | str 446 | end 447 | in 448 | fix_win32 exec 449 | 450 | let split s ch = 451 | let buf = Buffer.create 13 in 452 | let x = ref [] in 453 | let flush () = 454 | x := (Buffer.contents buf) :: !x; 455 | Buffer.clear buf 456 | in 457 | String.iter 458 | (fun c -> 459 | if c = ch then 460 | flush () 461 | else 462 | Buffer.add_char buf c) 463 | s; 464 | flush (); 465 | List.rev !x 466 | 467 | 468 | let split_nl s = split s '\n' 469 | 470 | 471 | let before_space s = 472 | try 473 | String.before s (String.index s ' ') 474 | with Not_found -> s 475 | 476 | (* ocamlfind command *) 477 | let ocamlfind x = S[Sh (exec_from_conf "ocamlfind"); x] 478 | 479 | (* This lists all supported packages. *) 480 | let find_packages () = 481 | List.map before_space (split_nl & run_and_read (exec_from_conf "ocamlfind" ^ " list")) 482 | 483 | 484 | (* Mock to list available syntaxes. *) 485 | let find_syntaxes () = ["camlp4o"; "camlp4r"] 486 | 487 | 488 | let well_known_syntax = [ 489 | "camlp4.quotations.o"; 490 | "camlp4.quotations.r"; 491 | "camlp4.exceptiontracer"; 492 | "camlp4.extend"; 493 | "camlp4.foldgenerator"; 494 | "camlp4.listcomprehension"; 495 | "camlp4.locationstripper"; 496 | "camlp4.macro"; 497 | "camlp4.mapgenerator"; 498 | "camlp4.metagenerator"; 499 | "camlp4.profiler"; 500 | "camlp4.tracer" 501 | ] 502 | 503 | 504 | let dispatch conf = 505 | function 506 | | After_options -> 507 | (* By using Before_options one let command line options have an higher 508 | * priority on the contrary using After_options will guarantee to have 509 | * the higher priority override default commands by ocamlfind ones *) 510 | Options.ocamlc := ocamlfind & A"ocamlc"; 511 | Options.ocamlopt := ocamlfind & A"ocamlopt"; 512 | Options.ocamldep := ocamlfind & A"ocamldep"; 513 | Options.ocamldoc := ocamlfind & A"ocamldoc"; 514 | Options.ocamlmktop := ocamlfind & A"ocamlmktop"; 515 | Options.ocamlmklib := ocamlfind & A"ocamlmklib" 516 | 517 | | After_rules -> 518 | 519 | (* When one link an OCaml library/binary/package, one should use 520 | * -linkpkg *) 521 | flag ["ocaml"; "link"; "program"] & A"-linkpkg"; 522 | 523 | if not (conf.no_automatic_syntax) then begin 524 | (* For each ocamlfind package one inject the -package option when 525 | * compiling, computing dependencies, generating documentation and 526 | * linking. *) 527 | List.iter 528 | begin fun pkg -> 529 | let base_args = [A"-package"; A pkg] in 530 | (* TODO: consider how to really choose camlp4o or camlp4r. *) 531 | let syn_args = [A"-syntax"; A "camlp4o"] in 532 | let (args, pargs) = 533 | (* Heuristic to identify syntax extensions: whether they end in 534 | ".syntax"; some might not. 535 | *) 536 | if Filename.check_suffix pkg "syntax" || 537 | List.mem pkg well_known_syntax then 538 | (syn_args @ base_args, syn_args) 539 | else 540 | (base_args, []) 541 | in 542 | flag ["ocaml"; "compile"; "pkg_"^pkg] & S args; 543 | flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S args; 544 | flag ["ocaml"; "doc"; "pkg_"^pkg] & S args; 545 | flag ["ocaml"; "link"; "pkg_"^pkg] & S base_args; 546 | flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S args; 547 | 548 | (* TODO: Check if this is allowed for OCaml < 3.12.1 *) 549 | flag ["ocaml"; "compile"; "package("^pkg^")"] & S pargs; 550 | flag ["ocaml"; "ocamldep"; "package("^pkg^")"] & S pargs; 551 | flag ["ocaml"; "doc"; "package("^pkg^")"] & S pargs; 552 | flag ["ocaml"; "infer_interface"; "package("^pkg^")"] & S pargs; 553 | end 554 | (find_packages ()); 555 | end; 556 | 557 | (* Like -package but for extensions syntax. Morover -syntax is useless 558 | * when linking. *) 559 | List.iter begin fun syntax -> 560 | flag ["ocaml"; "compile"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; 561 | flag ["ocaml"; "ocamldep"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; 562 | flag ["ocaml"; "doc"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; 563 | flag ["ocaml"; "infer_interface"; "syntax_"^syntax] & 564 | S[A"-syntax"; A syntax]; 565 | end (find_syntaxes ()); 566 | 567 | (* The default "thread" tag is not compatible with ocamlfind. 568 | * Indeed, the default rules add the "threads.cma" or "threads.cmxa" 569 | * options when using this tag. When using the "-linkpkg" option with 570 | * ocamlfind, this module will then be added twice on the command line. 571 | * 572 | * To solve this, one approach is to add the "-thread" option when using 573 | * the "threads" package using the previous plugin. 574 | *) 575 | flag ["ocaml"; "pkg_threads"; "compile"] (S[A "-thread"]); 576 | flag ["ocaml"; "pkg_threads"; "doc"] (S[A "-I"; A "+threads"]); 577 | flag ["ocaml"; "pkg_threads"; "link"] (S[A "-thread"]); 578 | flag ["ocaml"; "pkg_threads"; "infer_interface"] (S[A "-thread"]); 579 | flag ["ocaml"; "package(threads)"; "compile"] (S[A "-thread"]); 580 | flag ["ocaml"; "package(threads)"; "doc"] (S[A "-I"; A "+threads"]); 581 | flag ["ocaml"; "package(threads)"; "link"] (S[A "-thread"]); 582 | flag ["ocaml"; "package(threads)"; "infer_interface"] (S[A "-thread"]); 583 | 584 | | _ -> 585 | () 586 | end 587 | 588 | module MyOCamlbuildBase = struct 589 | (* # 22 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *) 590 | 591 | 592 | (** Base functions for writing myocamlbuild.ml 593 | @author Sylvain Le Gall 594 | *) 595 | 596 | 597 | 598 | 599 | 600 | open Ocamlbuild_plugin 601 | module OC = Ocamlbuild_pack.Ocaml_compiler 602 | 603 | 604 | type dir = string 605 | type file = string 606 | type name = string 607 | type tag = string 608 | 609 | 610 | (* # 62 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *) 611 | 612 | 613 | type t = 614 | { 615 | lib_ocaml: (name * dir list * string list) list; 616 | lib_c: (name * dir * file list) list; 617 | flags: (tag list * (spec OASISExpr.choices)) list; 618 | (* Replace the 'dir: include' from _tags by a precise interdepends in 619 | * directory. 620 | *) 621 | includes: (dir * dir list) list; 622 | } 623 | 624 | 625 | let env_filename = 626 | Pathname.basename 627 | BaseEnvLight.default_filename 628 | 629 | 630 | let dispatch_combine lst = 631 | fun e -> 632 | List.iter 633 | (fun dispatch -> dispatch e) 634 | lst 635 | 636 | 637 | let tag_libstubs nm = 638 | "use_lib"^nm^"_stubs" 639 | 640 | 641 | let nm_libstubs nm = 642 | nm^"_stubs" 643 | 644 | 645 | let dispatch t e = 646 | let env = 647 | BaseEnvLight.load 648 | ~filename:env_filename 649 | ~allow_empty:true 650 | () 651 | in 652 | match e with 653 | | Before_options -> 654 | let no_trailing_dot s = 655 | if String.length s >= 1 && s.[0] = '.' then 656 | String.sub s 1 ((String.length s) - 1) 657 | else 658 | s 659 | in 660 | List.iter 661 | (fun (opt, var) -> 662 | try 663 | opt := no_trailing_dot (BaseEnvLight.var_get var env) 664 | with Not_found -> 665 | Printf.eprintf "W: Cannot get variable %s\n" var) 666 | [ 667 | Options.ext_obj, "ext_obj"; 668 | Options.ext_lib, "ext_lib"; 669 | Options.ext_dll, "ext_dll"; 670 | ] 671 | 672 | | After_rules -> 673 | (* Declare OCaml libraries *) 674 | List.iter 675 | (function 676 | | nm, [], intf_modules -> 677 | ocaml_lib nm; 678 | let cmis = 679 | List.map (fun m -> (OASISString.uncapitalize_ascii m) ^ ".cmi") 680 | intf_modules in 681 | dep ["ocaml"; "link"; "library"; "file:"^nm^".cma"] cmis 682 | | nm, dir :: tl, intf_modules -> 683 | ocaml_lib ~dir:dir (dir^"/"^nm); 684 | List.iter 685 | (fun dir -> 686 | List.iter 687 | (fun str -> 688 | flag ["ocaml"; "use_"^nm; str] (S[A"-I"; P dir])) 689 | ["compile"; "infer_interface"; "doc"]) 690 | tl; 691 | let cmis = 692 | List.map (fun m -> dir^"/"^(OASISString.uncapitalize_ascii m)^".cmi") 693 | intf_modules in 694 | dep ["ocaml"; "link"; "library"; "file:"^dir^"/"^nm^".cma"] 695 | cmis) 696 | t.lib_ocaml; 697 | 698 | (* Declare directories dependencies, replace "include" in _tags. *) 699 | List.iter 700 | (fun (dir, include_dirs) -> 701 | Pathname.define_context dir include_dirs) 702 | t.includes; 703 | 704 | (* Declare C libraries *) 705 | List.iter 706 | (fun (lib, dir, headers) -> 707 | (* Handle C part of library *) 708 | flag ["link"; "library"; "ocaml"; "byte"; tag_libstubs lib] 709 | (S[A"-dllib"; A("-l"^(nm_libstubs lib)); A"-cclib"; 710 | A("-l"^(nm_libstubs lib))]); 711 | 712 | flag ["link"; "library"; "ocaml"; "native"; tag_libstubs lib] 713 | (S[A"-cclib"; A("-l"^(nm_libstubs lib))]); 714 | 715 | flag ["link"; "program"; "ocaml"; "byte"; tag_libstubs lib] 716 | (S[A"-dllib"; A("dll"^(nm_libstubs lib))]); 717 | 718 | (* When ocaml link something that use the C library, then one 719 | need that file to be up to date. 720 | This holds both for programs and for libraries. 721 | *) 722 | dep ["link"; "ocaml"; tag_libstubs lib] 723 | [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)]; 724 | 725 | dep ["compile"; "ocaml"; tag_libstubs lib] 726 | [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)]; 727 | 728 | (* TODO: be more specific about what depends on headers *) 729 | (* Depends on .h files *) 730 | dep ["compile"; "c"] 731 | headers; 732 | 733 | (* Setup search path for lib *) 734 | flag ["link"; "ocaml"; "use_"^lib] 735 | (S[A"-I"; P(dir)]); 736 | ) 737 | t.lib_c; 738 | 739 | (* Add flags *) 740 | List.iter 741 | (fun (tags, cond_specs) -> 742 | let spec = BaseEnvLight.var_choose cond_specs env in 743 | let rec eval_specs = 744 | function 745 | | S lst -> S (List.map eval_specs lst) 746 | | A str -> A (BaseEnvLight.var_expand str env) 747 | | spec -> spec 748 | in 749 | flag tags & (eval_specs spec)) 750 | t.flags 751 | | _ -> 752 | () 753 | 754 | 755 | let dispatch_default conf t = 756 | dispatch_combine 757 | [ 758 | dispatch t; 759 | MyOCamlbuildFindlib.dispatch conf; 760 | ] 761 | 762 | 763 | end 764 | 765 | 766 | # 766 "myocamlbuild.ml" 767 | open Ocamlbuild_plugin;; 768 | let package_default = 769 | { 770 | MyOCamlbuildBase.lib_ocaml = 771 | [ 772 | ("nodejs", ["src"], []); 773 | ("high_level", ["src/higher_level"], []); 774 | ("high_level_lwt", ["src/higher_level_lwt"], []) 775 | ]; 776 | lib_c = []; 777 | flags = 778 | [ 779 | (["oasis_library_nodejs_byte"; "ocaml"; "link"; "byte"], 780 | [ 781 | (OASISExpr.EBool true, 782 | S [A "-g"; A "-w"; A "+a-4-40..42-44-45-48"]) 783 | ]); 784 | (["oasis_library_nodejs_byte"; "ocaml"; "ocamldep"; "byte"], 785 | [ 786 | (OASISExpr.EBool true, 787 | S [A "-g"; A "-w"; A "+a-4-40..42-44-45-48"]) 788 | ]); 789 | (["oasis_library_nodejs_byte"; "ocaml"; "compile"; "byte"], 790 | [ 791 | (OASISExpr.EBool true, 792 | S [A "-g"; A "-w"; A "+a-4-40..42-44-45-48"]) 793 | ]); 794 | (["oasis_library_high_level_byte"; "ocaml"; "link"; "byte"], 795 | [ 796 | (OASISExpr.EBool true, 797 | S [A "-g"; A "-w"; A "+a-4-40..42-44-45-48"]) 798 | ]); 799 | (["oasis_library_high_level_byte"; "ocaml"; "ocamldep"; "byte"], 800 | [ 801 | (OASISExpr.EBool true, 802 | S [A "-g"; A "-w"; A "+a-4-40..42-44-45-48"]) 803 | ]); 804 | (["oasis_library_high_level_byte"; "ocaml"; "compile"; "byte"], 805 | [ 806 | (OASISExpr.EBool true, 807 | S [A "-g"; A "-w"; A "+a-4-40..42-44-45-48"]) 808 | ]); 809 | (["oasis_library_high_level_lwt_byte"; "ocaml"; "link"; "byte"], 810 | [ 811 | (OASISExpr.EBool true, 812 | S [A "-g"; A "-w"; A "+a-4-40..42-44-45-48"]) 813 | ]); 814 | (["oasis_library_high_level_lwt_byte"; "ocaml"; "ocamldep"; "byte"], 815 | [ 816 | (OASISExpr.EBool true, 817 | S [A "-g"; A "-w"; A "+a-4-40..42-44-45-48"]) 818 | ]); 819 | (["oasis_library_high_level_lwt_byte"; "ocaml"; "compile"; "byte"], 820 | [ 821 | (OASISExpr.EBool true, 822 | S [A "-g"; A "-w"; A "+a-4-40..42-44-45-48"]) 823 | ]) 824 | ]; 825 | includes = 826 | [ 827 | ("src/higher_level_lwt", ["src/higher_level"]); 828 | ("src/higher_level", ["src"]) 829 | ] 830 | } 831 | ;; 832 | 833 | let conf = {MyOCamlbuildFindlib.no_automatic_syntax = false} 834 | 835 | let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;; 836 | 837 | # 838 "myocamlbuild.ml" 838 | (* OASIS_STOP *) 839 | Ocamlbuild_plugin.dispatch dispatch_default;; 840 | -------------------------------------------------------------------------------- /opam/descr: -------------------------------------------------------------------------------- 1 | js_of_ocaml bindings for nodejs 2 | 3 | Write OCaml, run on node; these are js_of_ocaml bindings to the node 4 | JavaScript API. Get all the power of the node ecosystem with the type 5 | safety of OCaml. 6 | 7 | Here's how easy it is to make a server. 8 | 9 | 10 | Compile, run with: 11 | 12 | $ ocamlfind ocamlc c.ml -linkpkg -package nodejs.high_level -o T.out 13 | $ js_of_ocaml T.out 14 | $ node T.js -------------------------------------------------------------------------------- /opam/findlib: -------------------------------------------------------------------------------- 1 | nodejs 2 | -------------------------------------------------------------------------------- /opam/opam: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | opam-version: "1.2" 3 | name: "nodejs" 4 | version: "1.0.0" 5 | maintainer: "Edgar Aroutiounian " 6 | authors: [ "Edgar Aroutiounian " ] 7 | license: "BSD-3-clause" 8 | homepage: "https://github.com/fxfactorial/ocaml-nodejs" 9 | dev-repo: "https://github.com/fxfactorial/ocaml-nodejs.git" 10 | bug-reports: "https://github.com/fxfactorial/ocaml-nodejs/issues" 11 | build: [ 12 | ["ocaml" "setup.ml" "-configure" "--prefix" prefix] 13 | ["ocaml" "setup.ml" "-build"] 14 | ] 15 | install: ["ocaml" "setup.ml" "-install"] 16 | remove: [ 17 | ["ocamlfind" "remove" "nodejs"] 18 | ] 19 | build-test: [ 20 | ["ocaml" "setup.ml" "-configure" "--enable-tests"] 21 | ["ocaml" "setup.ml" "-build"] 22 | ["ocaml" "setup.ml" "-test"] 23 | ] 24 | depends: [ 25 | "js_of_ocaml" {>= "2.8.1"} 26 | "lwt" {>= "2.5.2"} 27 | "ocamlfind" {build} 28 | "oasis" 29 | ] 30 | available: [ ocaml-version >= "4.02.3" ] 31 | 32 | depexts: [ 33 | [["debian"] ["nodejs"]] 34 | [["homebrew" "osx"] ["node"]] 35 | [["ubuntu"] ["nodejs"]] 36 | ] 37 | 38 | post-messages: [ 39 | "Now you can write OCaml and execute on node." 40 | "Example assuming file name of c.ml:" 41 | " 42 | " 43 | "ocamlfind ocamlc c.ml -linkpkg -package nodejs -o T.out" 44 | "js_of_ocaml T.out" 45 | "node T.js" 46 | ] 47 | -------------------------------------------------------------------------------- /setup.ml: -------------------------------------------------------------------------------- 1 | (* setup.ml generated for the first time by OASIS v0.4.5 *) 2 | 3 | (* OASIS_START *) 4 | (* DO NOT EDIT (digest: 9852805d5c19ca1cb6abefde2dcea323) *) 5 | (******************************************************************************) 6 | (* OASIS: architecture for building OCaml libraries and applications *) 7 | (* *) 8 | (* Copyright (C) 2011-2013, Sylvain Le Gall *) 9 | (* Copyright (C) 2008-2011, OCamlCore SARL *) 10 | (* *) 11 | (* This library is free software; you can redistribute it and/or modify it *) 12 | (* under the terms of the GNU Lesser General Public License as published by *) 13 | (* the Free Software Foundation; either version 2.1 of the License, or (at *) 14 | (* your option) any later version, with the OCaml static compilation *) 15 | (* exception. *) 16 | (* *) 17 | (* This library is distributed in the hope that it will be useful, but *) 18 | (* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *) 19 | (* or FITNESS FOR A PARTICULAR PURPOSE. See the file COPYING for more *) 20 | (* details. *) 21 | (* *) 22 | (* You should have received a copy of the GNU Lesser General Public License *) 23 | (* along with this library; if not, write to the Free Software Foundation, *) 24 | (* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *) 25 | (******************************************************************************) 26 | 27 | let () = 28 | try 29 | Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH") 30 | with Not_found -> () 31 | ;; 32 | #use "topfind";; 33 | #require "oasis.dynrun";; 34 | open OASISDynRun;; 35 | 36 | (* OASIS_STOP *) 37 | let () = setup ();; 38 | -------------------------------------------------------------------------------- /src/META: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 6a9fa993d66c7c4cc0616548c2524e17) 3 | version = "1.0.0" 4 | description = "js_of_ocaml bindings for nodejs" 5 | requires = "js_of_ocaml js_of_ocaml.ppx lwt.ppx lwt" 6 | archive(byte) = "nodejs.cma" 7 | archive(byte, plugin) = "nodejs.cma" 8 | exists_if = "nodejs.cma" 9 | package "high_level_lwt" ( 10 | version = "1.0.0" 11 | description = "js_of_ocaml bindings for nodejs" 12 | requires = "nodejs.high_level" 13 | archive(byte) = "high_level_lwt.cma" 14 | archive(byte, plugin) = "high_level_lwt.cma" 15 | exists_if = "high_level_lwt.cma" 16 | ) 17 | 18 | package "high_level" ( 19 | version = "1.0.0" 20 | description = "js_of_ocaml bindings for nodejs" 21 | requires = "nodejs" 22 | archive(byte) = "high_level.cma" 23 | archive(byte, plugin) = "high_level.cma" 24 | exists_if = "high_level.cma" 25 | ) 26 | # OASIS_STOP 27 | 28 | -------------------------------------------------------------------------------- /src/higher_level/high_level.mldylib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 1e86897f6195533f4aa156440679fd4e) 3 | Nodejs_high_level 4 | # OASIS_STOP 5 | -------------------------------------------------------------------------------- /src/higher_level/high_level.mllib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 1e86897f6195533f4aa156440679fd4e) 3 | Nodejs_high_level 4 | # OASIS_STOP 5 | -------------------------------------------------------------------------------- /src/higher_level/higher_level.mldylib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 1e86897f6195533f4aa156440679fd4e) 3 | Nodejs_high_level 4 | # OASIS_STOP 5 | -------------------------------------------------------------------------------- /src/higher_level/higher_level.mllib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 1e86897f6195533f4aa156440679fd4e) 3 | Nodejs_high_level 4 | # OASIS_STOP 5 | -------------------------------------------------------------------------------- /src/higher_level/nodejs_high_level.ml: -------------------------------------------------------------------------------- 1 | let __filename () = Nodejs.__filename () |> Js.to_string 2 | 3 | let __dirname () = Nodejs.__dirname () |> Js.to_string 4 | 5 | 6 | module Buffer = struct 7 | 8 | type exn += Buffer_not_init 9 | 10 | class buffer ?(default=1024) fresh_buffer = object 11 | 12 | val mutable buffer_handle : Nodejs.Buffer.buffer Js.t Js.opt = Js.null 13 | val mutable init_buffer = false 14 | 15 | initializer 16 | if fresh_buffer 17 | then buffer_handle <- 18 | Nodejs.Buffer.buffer_static##alloc default |> Js.Opt.return; 19 | init_buffer <- true 20 | 21 | method set_handle new_handle = 22 | buffer_handle <- new_handle |> Js.Opt.return; 23 | init_buffer <- true 24 | 25 | method to_string = 26 | if init_buffer then begin 27 | let b = Js.Opt.get buffer_handle (fun _ -> assert false) in 28 | b##toString |> Js.to_string 29 | end else raise Buffer_not_init 30 | 31 | end 32 | 33 | end 34 | 35 | 36 | module Events = struct 37 | 38 | class event_emmiter = object 39 | val k = new%js Nodejs.Events.event_emitter 40 | method event_names = 41 | k##eventNames 42 | |> Js.str_array 43 | |> Js.to_array 44 | |> Array.map Js.to_string 45 | |> Array.to_list 46 | 47 | method add_listener : 'a 'b. string -> ('a -> 'b) -> unit = fun event_name callback -> 48 | k##addListener (Js.string event_name) (Js.wrap_callback callback) 49 | 50 | method emit event_name = k##emit (Js.string event_name) 51 | 52 | end 53 | 54 | end 55 | 56 | module Fs = struct 57 | 58 | type flag = Read | Write | Read_write 59 | 60 | let string_of_flag = function Read -> "r" | Write -> "w" | Read_write -> "rw" 61 | 62 | let read_file_sync file_name file_flag = 63 | let result = 64 | Nodejs.Fs.fs##readFileSync 65 | (Js.string file_name) 66 | (object%js 67 | val encoding = Js.null 68 | val flag = Js.string (string_of_flag file_flag) 69 | end) 70 | in 71 | result##toString |> Js.to_string 72 | 73 | let read_file_async file_name callback = 74 | let wrapped = fun err given_buffer -> 75 | let b = new Buffer.buffer false in 76 | b#set_handle given_buffer; 77 | callback err b 78 | in 79 | Nodejs.Fs.fs##readFile (Js.string file_name) (Js.wrap_callback wrapped) 80 | 81 | end 82 | 83 | module Net = struct 84 | 85 | type exn += Socket_not_init 86 | 87 | class socket fresh_socket = object 88 | 89 | val mutable socket_handle : Nodejs.Net.socket Js.t Js.opt = Js.null 90 | val mutable init_socket = false 91 | 92 | initializer 93 | if fresh_socket 94 | then socket_handle <- new%js Nodejs.Net.socket |> Js.Opt.return; 95 | init_socket <- true 96 | 97 | method set_handle raw_socket = 98 | socket_handle <- raw_socket |> Js.Opt.return; 99 | init_socket <- true 100 | 101 | method write data = 102 | if init_socket then begin 103 | let c = Js.Opt.get socket_handle (fun _ -> assert false) in 104 | c##write (Nodejs.Buffer.buffer_static##from (Js.string data)) 105 | end else raise Socket_not_init 106 | 107 | end 108 | 109 | 110 | class server listener = object 111 | val k = 112 | let wrapped = fun given_socket -> 113 | let s = new socket false in 114 | s#set_handle given_socket; 115 | listener s 116 | in 117 | Nodejs.Net.net##createServer_withConnListener (Js.wrap_callback wrapped) 118 | (* method listen : 'a 'b. int -> ('a -> 'b) -> unit = fun port callback -> *) 119 | (* k##listen port (Js.wrap_callback callback) *) 120 | method listen port callback = k##listen port (Js.wrap_callback callback) 121 | 122 | end 123 | 124 | (* let create_server listener = *) 125 | (* Nodejs.Net.net##createServer_withConnListener (Js.wrap_callback listener) *) 126 | end 127 | 128 | module Os = struct 129 | 130 | (* Later hide with mli *) 131 | let os_handle = Nodejs.Os.os 132 | 133 | type cpu_stat = { model: string; 134 | speed: int; 135 | times: } 140 | 141 | type endianess = Big | Little 142 | 143 | type platform = Aix | Darwin | Freebsd | Linux | Openbsd | Sunos | Win32 | Android 144 | 145 | (* Hide as well in mli *) 146 | let endianess_of_string = 147 | function "BE" -> Big | "LE" -> Little | _ -> assert false 148 | 149 | let platform_of_string = function 150 | | "aix" -> Aix 151 | | "darwin" -> Darwin 152 | | "freebsd" -> Freebsd 153 | | "linux" -> Linux 154 | (* TODO FINISH*) 155 | | _ -> assert false 156 | 157 | let cpu_stats () = 158 | os_handle##cpus 159 | |> Js.to_array 160 | |> Array.map (fun c -> 161 | {model = c##.model |> Js.to_string; 162 | speed = c##.speed; 163 | times = object 164 | method user = c##.times##.user 165 | method nice = c##.times##.nice 166 | method sys = c##.times##.sys 167 | method idle = c##.times##.idle 168 | method irq = c##.times##.irq 169 | end} 170 | ) 171 | |> Array.to_list 172 | 173 | let endianess () = 174 | os_handle##endianness |> Js.to_string |> endianess_of_string 175 | 176 | let free_memory_available () = os_handle##freemem 177 | 178 | let home_directory () = os_handle##homedir |> Js.to_string 179 | 180 | let hostname () = os_handle##hostname |> Js.to_string 181 | 182 | let load_average () = os_handle##loadavg |> Js.to_array 183 | 184 | end 185 | 186 | class process = object 187 | val js = Nodejs.process 188 | method arguments = 189 | js##.argv |> Js.to_array |> Array.map Js.to_string |> Array.to_list 190 | method abort = js##abort 191 | method arch = js##.arch |> Js.to_string 192 | method change_dir s = js##chdir (Js.string s) 193 | method config : 'a. 'a Js.t = js##.config 194 | method connect = js##.connected |> Js.to_bool 195 | method current_working_directory = js##cwd |> Js.to_string 196 | method environment_variables : 'b. 'b Js.t = js##.env 197 | method pid = js##.pid 198 | method exit e = js##exit e 199 | end 200 | 201 | let process = new process 202 | -------------------------------------------------------------------------------- /src/higher_level_lwt/high_level_lwt.mldylib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 8799187c1c9c2dd0ce6ec0d2748aa58b) 3 | Nodejs_high_level_lwt 4 | # OASIS_STOP 5 | -------------------------------------------------------------------------------- /src/higher_level_lwt/high_level_lwt.mllib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 8799187c1c9c2dd0ce6ec0d2748aa58b) 3 | Nodejs_high_level_lwt 4 | # OASIS_STOP 5 | -------------------------------------------------------------------------------- /src/higher_level_lwt/nodejs_high_level_lwt.ml: -------------------------------------------------------------------------------- 1 | 2 | module Fs = struct 3 | 4 | let read_file filename = 5 | let t, w = Lwt.task () in 6 | Nodejs_high_level.Fs.read_file_async 7 | filename 8 | (fun err content -> Lwt.wakeup w (err, content)); 9 | t 10 | 11 | end 12 | 13 | -------------------------------------------------------------------------------- /src/nodejs.ml: -------------------------------------------------------------------------------- 1 | (** Raw call for doing require("some_module") *) 2 | 3 | module Bindings_utils = struct 4 | 5 | let require_module s = 6 | Js.Unsafe.fun_call 7 | (Js.Unsafe.js_expr "require") 8 | [|Js.Unsafe.inject (Js.string s)|] 9 | 10 | let ( !@ ) f = Js.wrap_callback f 11 | let ( !! ) o = Js.Unsafe.inject o 12 | 13 | (** Get the field of a JavaScript Object *) 14 | let ( ) obj field = Js.Unsafe.get obj field 15 | 16 | (** Same as console.log *) 17 | let log obj = Firebug.console##log obj 18 | 19 | (** Call method of a JavaScript object *) 20 | let m = Js.Unsafe.meth_call 21 | 22 | (** Inject something as a JS object, be sure its Js.t already, 23 | functions seemingly exempt *) 24 | let i = Js.Unsafe.inject 25 | 26 | (** Turn a JavaScript Object into a string *) 27 | let stringify o = Js._JSON##stringify o |> Js.to_string 28 | 29 | (** Turn an OCaml string into a JavaScript string *) 30 | let to_js_str s = Js.string s |> Js.Unsafe.inject 31 | 32 | (** Turn a string into a JSON object *) 33 | let json_of_string s = Js._JSON##parse (s |> Js.string) 34 | 35 | (** Create a JavaScript Object out of an alist *) 36 | let obj_of_alist a_l = 37 | List.map (fun (key, value) -> (key, Js.Unsafe.inject value)) a_l 38 | |> Array.of_list |> Js.Unsafe.obj 39 | 40 | (** Turn JavaScript string array into OCaml list of string *) 41 | let to_string_list g = 42 | g |> Js.str_array |> Js.to_array |> Array.map Js.to_string |> Array.to_list 43 | 44 | (** Turn OCaml list of strings into JavaScript string array *) 45 | let of_string_list g = 46 | g |> Array.of_list |> Array.map Js.string |> Js.array 47 | 48 | (** Get all keys of an Object *) 49 | let keys obj = 50 | m (Js.Unsafe.variable "Object") "keys" [|obj|] 51 | |> Js.to_array |> Array.map Js.to_string |> Array.to_list 52 | 53 | (** Call a function for each value of each key in an Object, throw 54 | away result *) 55 | let for_each_iter ~f obj = 56 | keys obj |> List.iter (fun k -> f (Js.Unsafe.get obj k)) 57 | 58 | (** Call a function for each value of each key in an Object, keep 59 | result *) 60 | let for_each_map ~f obj = 61 | keys obj |> List.map (fun k -> f k (Js.Unsafe.get obj k)) 62 | 63 | let debug thing field = 64 | Firebug.console##log (m (thing field) "toString" [||]); 65 | 66 | end 67 | 68 | type error_arg = Js.error Js.opt 69 | 70 | let __filename () = (Js.Unsafe.eval_string "__filename" : Js.js_string Js.t) 71 | 72 | let __dirname () = (Js.Unsafe.eval_string "__dirname" : Js.js_string Js.t) 73 | 74 | module Events = struct 75 | 76 | class type event_emitter = object('self) 77 | (* method on : Js.js_string Js.t -> 'a Js.callback -> unit Js.meth *) 78 | method on_withNoArgs : 79 | Js.js_string Js.t -> 80 | (unit -> unit) Js.callback -> 81 | unit Js.meth 82 | method on_WithOneArg : 83 | Js.js_string Js.t -> 84 | (Js.Unsafe.any Js.t -> unit) Js.callback -> 85 | unit Js.meth 86 | method on_WithTwoArg : 87 | Js.js_string Js.t -> 88 | (Js.Unsafe.any Js.t -> Js.Unsafe.any Js.t -> unit) Js.callback -> 89 | unit Js.meth 90 | method emit : Js.js_string Js.t -> unit Js.meth 91 | method emit_withArg : Js.js_string Js.t -> 'a Js.t -> unit Js.meth 92 | method emit_withTwoArgs : 93 | Js.js_string Js.t -> 'a Js.t -> 'b Js.t -> unit Js.meth 94 | method getMaxListeners : int Js.meth 95 | 96 | method once : Js.js_string Js.t -> 'a Js.callback -> unit Js.meth 97 | 98 | method addListener : Js.js_string Js.t -> 'a Js.callback -> unit Js.meth 99 | 100 | method eventNames : Js.string_array Js.t Js.meth 101 | 102 | end 103 | 104 | let event_emitter : event_emitter Js.t Js.constr = 105 | Bindings_utils.require_module "events" 106 | 107 | end 108 | 109 | module Buffer = struct 110 | 111 | class type buffer = object 112 | method length : int Js.readonly_prop 113 | method toString : Js.js_string Js.t Js.meth 114 | method toJSON : 'a. 'a Js.t Js.meth 115 | method swap16 : buffer Js.t Js.meth 116 | method swap32 : buffer Js.t Js.meth 117 | 118 | end 119 | 120 | class type buffer_static = object 121 | method from_array : Typed_array.uint16Array -> buffer Js.t Js.meth 122 | method from : Js.js_string Js.t -> buffer Js.t Js.meth 123 | method from_withEncoding : 124 | Js.js_string Js.t -> Js.js_string Js.t -> buffer Js.t Js.meth 125 | method alloc : int -> buffer Js.t Js.meth 126 | method compare : buffer Js.t -> buffer Js.t -> bool Js.t Js.meth 127 | method isBuffer : 'a Js.t -> bool Js.t Js.meth 128 | method isEncoding : Js.js_string Js.t -> bool Js.t Js.meth 129 | end 130 | 131 | let buffer_static : buffer_static Js.t = Js.Unsafe.pure_js_expr "Buffer" 132 | 133 | end 134 | 135 | module Stream = struct 136 | 137 | class type stream = object('self) 138 | inherit Events.event_emitter 139 | end 140 | 141 | class type writable_stream = object('self) 142 | inherit stream 143 | (* method cork *) 144 | (* method end_ *) 145 | (* method setDefaultEncoding *) 146 | (* method uncork *) 147 | (* method write *) 148 | end 149 | 150 | class type readable_stream = object('self) 151 | inherit stream 152 | method isPaused : bool Js.t Js.meth 153 | method pause : readable_stream Js.t Js.meth 154 | method pipe : 'self Js.t -> writable_stream Js.t Js.meth 155 | 156 | (* method pipe_with_options : *) 157 | (* writable_stream Js.t -> *) 158 | (* #stream Js.t Js.meth *) 159 | 160 | method read : 'a Js.t Js.opt Js.meth 161 | method read_withAmount : int -> 'a Js.t Js.opt Js.meth 162 | method resume : readable_stream Js.t Js.meth 163 | method setEncoding : Js.js_string Js.t -> readable_stream Js.t Js.meth 164 | method unpipe : unit Js.meth 165 | method unpipe_withDest : writable_stream Js.t -> unit Js.meth 166 | method unshift : Buffer.buffer Js.t -> unit Js.meth 167 | method unshift_withString : Js.js_string Js.t -> unit Js.meth 168 | 169 | end 170 | 171 | let stream : stream Js.t = Bindings_utils.require_module "stream" 172 | 173 | end 174 | 175 | module Net = struct 176 | class type socket = object 177 | (* Actually they are both read and writeable *) 178 | inherit Stream.readable_stream 179 | 180 | method address : 'a Js.t Js.meth 181 | method bufferSize : int Js.readonly_prop 182 | method bytesRead : int Js.readonly_prop 183 | method bytesWritten : int Js.readonly_prop 184 | method connect : 185 | Js.t 192 | (* Many more connect methods needed *) 193 | (* method connect_with_listener : *) 194 | method connecting : bool Js.t Js.readonly_prop 195 | 196 | method destroy : unit Js.meth 197 | method destroy_with_exception : 'a Js.t -> unit Js.meth 198 | method destroyed : bool Js.t Js.readonly_prop 199 | method end_ : unit Js.meth 200 | method end_with_data : Buffer.buffer Js.t -> unit Js.meth 201 | method end_with_data_and_encoding : 202 | Buffer.buffer Js.t -> Js.js_string Js.t -> unit Js.meth 203 | method localAddress : Js.js_string Js.t Js.readonly_prop 204 | method localPort : int Js.readonly_prop 205 | (* method! pause : unit Js.meth *) 206 | method ref : unit Js.meth 207 | method remoteAddress : Js.js_string Js.t Js.readonly_prop 208 | method remoteFamily : Js.js_string Js.t Js.readonly_prop 209 | method remotePort : int Js.readonly_prop 210 | (* method resume : unit Js.meth *) 211 | (* method setEncoding : unit Js.meth *) 212 | method setEncoding_with_encoding : Js.js_string Js.t -> unit Js.meth 213 | method setKeepAlive : socket Js.t Js.meth 214 | method setKeepAlive_withDelay : bool Js.t-> int -> socket Js.t Js.meth 215 | method setNoDelay : socket Js.t Js.meth 216 | method setNoDeplay_withBool : bool Js.t -> socket Js.t Js.meth 217 | 218 | method write : Buffer.buffer Js.t -> unit Js.meth 219 | method write_withEncoding : 220 | Buffer.buffer Js.t -> Js.js_string Js.t -> unit Js.meth 221 | method write_withEncodingAndCallback : 222 | Buffer.buffer Js.t -> Js.js_string Js.t -> 'a Js.callback -> unit Js.meth 223 | 224 | end 225 | 226 | and server = object 227 | inherit Events.event_emitter 228 | method address : Js.t Js.meth 231 | method close : unit Js.meth 232 | method close_withCallback : (error_arg -> unit) Js.callback Js.meth 233 | method getConnections : (error_arg -> int -> unit) Js.callback Js.meth 234 | (* Later type it, a server or socket *) 235 | method listen : int -> (unit -> unit) Js.callback -> unit Js.meth 236 | 237 | method maxConnections : int Js.prop 238 | method listening : bool Js.t Js.readonly_prop 239 | end 240 | and net = object 241 | (* method connect : Js.t *) 242 | method createServer : server Js.t Js.meth 243 | method createServer_withConnListener : 244 | (socket Js.t -> unit) Js.callback -> server Js.t Js.meth 245 | method createServer_withOptionsAndConnListener : 246 | Js.t -> 248 | server Js.t Js.meth 249 | 250 | end 251 | 252 | (* let socket_with_options : 'a. *) 253 | (* ( Js.t -> socket Js.t) Js.constr = fun item -> *) 257 | (* (Bindings_utils.require_module "net")##.Socket *) 258 | 259 | let socket : socket Js.t Js.constr = 260 | (Bindings_utils.require_module "net")##.Socket 261 | 262 | let net : net Js.t = Bindings_utils.require_module "net" 263 | 264 | end 265 | 266 | (* module Dns = struct *) 267 | (* class type dns = object *) 268 | (* method lookup : *) 269 | (* Js.js_string Js.t -> *) 270 | (* (Js.error -> Js.js_string Js.t -> int -> unit) Js.callback -> *) 271 | (* unit Js.meth *) 272 | 273 | (* method resolve4 : *) 274 | (* Js.js_string Js.t -> *) 275 | (* (Js.string_array Js.t -> unit) Js.callback -> *) 276 | (* unit Js.meth *) 277 | 278 | (* end *) 279 | 280 | (* let dns : dns Js.t = Bindings_utils.require_module "dns" *) 281 | 282 | (* end *) 283 | 284 | 285 | module Fs = struct 286 | 287 | class type fs = object 288 | method readFileSync : 289 | Js.js_string Js.t -> 290 | Js.t -> 292 | Buffer.buffer Js.t Js.meth 293 | 294 | method readFile : 295 | Js.js_string Js.t -> 296 | (Js.error Js.t -> Buffer.buffer Js.t -> unit) Js.callback -> 297 | unit Js.meth 298 | 299 | end 300 | 301 | let fs : fs Js.t = Bindings_utils.require_module "fs" 302 | 303 | end 304 | 305 | module Os = struct 306 | 307 | class type os = object 308 | method _EOL : Js.js_string Js.t Js.readonly_prop 309 | method arch : Js.js_string Js.t Js.meth 310 | (* method constants *) 311 | method cpus : 312 | Js.t Js.readonly_prop> 319 | Js.t Js.js_array Js.t Js.meth 320 | method endianness : Js.js_string Js.t Js.meth 321 | method freemem : int Js.meth 322 | method homedir : Js.js_string Js.t Js.meth 323 | method hostname : Js.js_string Js.t Js.meth 324 | method loadavg : int Js.js_array Js.t Js.meth 325 | 326 | end 327 | 328 | let os : os Js.t = Bindings_utils.require_module "os" 329 | 330 | end 331 | 332 | module Http = struct 333 | 334 | class type agent = object 335 | (* method createConnection *) 336 | (* method destroy *) 337 | (* method freeSockets *) 338 | (* method getName *) 339 | (* method maxFreeSockets *) 340 | (* method maxSockets *) 341 | (* method requests *) 342 | (* method sockets *) 343 | end 344 | 345 | class type client_request = object 346 | inherit Stream.writable_stream 347 | 348 | end 349 | 350 | let agent : agent Js.t = (Bindings_utils.require_module "http")##.Agent 351 | 352 | let agent_with_options : 353 | ( Js.t -> agent Js.t) Js.constr = 357 | (Bindings_utils.require_module "http")##.Agent 358 | 359 | end 360 | 361 | class type process = object 362 | inherit Events.event_emitter 363 | method argv : Js.js_string Js.t Js.js_array Js.t Js.readonly_prop 364 | method abort : unit Js.meth 365 | method arch : Js.js_string Js.t Js.readonly_prop 366 | method chdir : Js.js_string Js.t -> unit Js.meth 367 | method config : 'a Js.t Js.readonly_prop 368 | method connected : bool Js.t Js.readonly_prop 369 | method cwd : Js.js_string Js.t Js.meth 370 | method disconnect : unit Js.meth 371 | method env : 'a Js.t Js.readonly_prop 372 | (* Many more missing *) 373 | method pid : int Js.readonly_prop 374 | method exit : int -> unit Js.meth 375 | end 376 | 377 | let process : process Js.t = Js.Unsafe.variable "process" 378 | -------------------------------------------------------------------------------- /src/nodejs.mldylib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 4b00bbf4971bea7d45e4ee343c881d44) 3 | Nodejs 4 | # OASIS_STOP 5 | -------------------------------------------------------------------------------- /src/nodejs.mllib: -------------------------------------------------------------------------------- 1 | # OASIS_START 2 | # DO NOT EDIT (digest: 4b00bbf4971bea7d45e4ee343c881d44) 3 | Nodejs 4 | # OASIS_STOP 5 | --------------------------------------------------------------------------------