├── .eslintignore ├── dune-project ├── .dockerignore ├── bootstrap ├── shared ├── dune └── feed.ml ├── public ├── favicon.ico ├── manifest.json └── index.html ├── esy.lock ├── .gitignore ├── .gitattributes ├── opam │ ├── ocamlfind.1.8.1 │ │ ├── files │ │ │ ├── ocaml-stub │ │ │ └── ocamlfind.install │ │ └── opam │ ├── base-unix.base │ │ └── opam │ ├── base-threads.base │ │ └── opam │ ├── conf-m4.1 │ │ └── opam │ ├── fix.20201120 │ │ └── opam │ ├── ppx_derivers.1.2.1 │ │ └── opam │ ├── result.1.5 │ │ └── opam │ ├── menhir.20210310 │ │ └── opam │ ├── menhirLib.20210310 │ │ └── opam │ ├── menhirSdk.20210310 │ │ └── opam │ ├── dot-merlin-reader.4.1 │ │ └── opam │ ├── merlin-extend.0.6 │ │ └── opam │ ├── yojson.1.7.0 │ │ └── opam │ ├── cppo.1.6.7 │ │ └── opam │ ├── easy-format.1.3.2 │ │ └── opam │ ├── biniou.1.2.1 │ │ └── opam │ ├── csexp.1.4.0 │ │ └── opam │ ├── dune.2.8.4 │ │ └── opam │ └── merlin.4.1-412 │ │ └── opam ├── overrides │ ├── opam__s__conf_m4_opam__c__1_opam_override │ │ └── package.json │ └── opam__s__ocamlfind_opam__c__1.8.1_opam_override │ │ ├── package.json │ │ └── files │ │ └── findlib-1.8.1.patch └── index.json ├── lambda ├── util.ml ├── dune └── lambda.ml ├── .nowignore ├── dune ├── src ├── units.scss ├── ui.re ├── App.test.js ├── palette.scss ├── request.ml ├── index.scss ├── Ui.module.scss ├── api.re ├── let_syntax.ml ├── decode_feed.ml ├── index.re ├── utils.ml ├── App.module.scss ├── logo.svg ├── App.re └── serviceWorker.js ├── nix ├── default.nix ├── ci.nix └── generic.nix ├── .github └── workflows │ └── test.yml ├── bsconfig.json ├── .gitignore ├── shell.nix ├── esy.json ├── flake.nix ├── .ocamlformat ├── LICENSE ├── now.json ├── package.json ├── Dockerfile ├── flake.lock └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | *.bs.js 2 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 3.1) 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | _esy 2 | /node_modules 3 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anmonteiro/gh-feed-reader/HEAD/bootstrap -------------------------------------------------------------------------------- /shared/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name feed) 3 | (preprocess 4 | (pps ppx_deriving_yojson))) 5 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anmonteiro/gh-feed-reader/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /esy.lock/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Reset any possible .gitignore, we want all esy.lock to be un-ignored. 3 | !* 4 | -------------------------------------------------------------------------------- /lambda/util.ml: -------------------------------------------------------------------------------- 1 | module Option = struct 2 | let map ~f = function None -> None | Some x -> Some (f x) 3 | end 4 | -------------------------------------------------------------------------------- /esy.lock/.gitattributes: -------------------------------------------------------------------------------- 1 | 2 | # Set eol to LF so files aren't converted to CRLF-eol on Windows. 3 | * text eol=lf linguist-generated 4 | -------------------------------------------------------------------------------- /.nowignore: -------------------------------------------------------------------------------- 1 | /* 2 | !bootstrap 3 | !cacert.pem 4 | !package.json 5 | !src 6 | !shared 7 | !bsconfig.json 8 | !public 9 | !yarn.lock 10 | !vendor 11 | -------------------------------------------------------------------------------- /dune: -------------------------------------------------------------------------------- 1 | (env 2 | (release 3 | (ocamlopt_flags 4 | (:standard -O3 -unbox-closures)))) 5 | 6 | ;;;;{BSB GENERATED: NO EDIT;;;;BSB GENERATED: NO EDIT} 7 | -------------------------------------------------------------------------------- /esy.lock/opam/ocamlfind.1.8.1/files/ocaml-stub: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BINDIR=$(dirname "$(command -v ocamlc)") 4 | "$BINDIR/ocaml" -I "$OCAML_TOPLEVEL_PATH" "$@" 5 | -------------------------------------------------------------------------------- /src/units.scss: -------------------------------------------------------------------------------- 1 | @function unit($value) { 2 | @return $value * 16px; 3 | } 4 | 5 | $xs: unit(0.25); 6 | $s: unit(0.5); 7 | $m: unit(1); 8 | $l: unit(2); 9 | $xl: unit(4); 10 | -------------------------------------------------------------------------------- /esy.lock/opam/base-unix.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "https://github.com/ocaml/opam-repository/issues" 3 | description: """ 4 | Unix library distributed with the OCaml compiler 5 | """ 6 | 7 | -------------------------------------------------------------------------------- /esy.lock/opam/base-threads.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "https://github.com/ocaml/opam-repository/issues" 3 | description: """ 4 | Threads library distributed with the OCaml compiler 5 | """ 6 | 7 | -------------------------------------------------------------------------------- /esy.lock/overrides/opam__s__conf_m4_opam__c__1_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": "true", 3 | "dependencies": { 4 | "esy-m4": "esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /esy.lock/opam/ocamlfind.1.8.1/files/ocamlfind.install: -------------------------------------------------------------------------------- 1 | bin: [ 2 | "src/findlib/ocamlfind" {"ocamlfind"} 3 | "?src/findlib/ocamlfind_opt" {"ocamlfind"} 4 | "?tools/safe_camlp4" 5 | ] 6 | toplevel: ["src/findlib/topfind"] 7 | -------------------------------------------------------------------------------- /src/ui.re: -------------------------------------------------------------------------------- 1 | [@bs.module] external css: Js.t({..}) as 'a = "./Ui.module.scss"; 2 | 3 | module Card = { 4 | [@react.component] 5 | let make = (~children) => { 6 |
7 |
children
8 |
; 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /lambda/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name lambda) 3 | (libraries lambda-runtime vercel piaf lwt_ssl logs.fmt fmt.tty uri syndic 4 | lambdasoup feed) 5 | (preprocess 6 | (pps ppx_deriving_yojson))) 7 | 8 | (env 9 | (static 10 | (flags 11 | (:standard -ccopt -static)) 12 | (ocamlopt_flags 13 | (:standard -O3 -unbox-closures)))) 14 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /nix/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | let 4 | inherit (pkgs) lib callPackage pkgsCross; 5 | in 6 | { 7 | native = callPackage ./generic.nix { 8 | inherit (lib) filterGitSource; 9 | }; 10 | 11 | musl64 = 12 | let pkgs = pkgsCross.musl64; 13 | in 14 | pkgs.callPackage ./generic.nix { 15 | static = true; 16 | inherit (lib) filterGitSource; 17 | ocamlPackages = pkgs.ocamlPackages; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "Build" 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | tests: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: cachix/install-nix-action@v16 13 | - uses: cachix/cachix-action@v10 14 | with: 15 | name: anmonteiro 16 | signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}' 17 | - name: "Run nix-build" 18 | run: nix-build ./nix/ci.nix 19 | -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reason-scripts", 3 | "sources": [ 4 | "src", 5 | "shared" 6 | ], 7 | "bs-dependencies": [ 8 | "@rescript/react", 9 | "bs-decoders", 10 | "bs-fetch", 11 | "reason-promise" 12 | ], 13 | "warnings": { 14 | "error": "+A", 15 | "number": "-44-101" 16 | }, 17 | "refmt": 3, 18 | "reason": { 19 | "react-jsx": 3 20 | }, 21 | "package-specs": { 22 | "module": "es6", 23 | "in-source": true 24 | }, 25 | "suffix": ".bs.js" 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # OCaml / BuckleScript 26 | .merlin 27 | _build 28 | _esy 29 | *.bs.js 30 | lib/ 31 | .bsb.lock 32 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | with pkgs; 4 | 5 | mkShell { 6 | buildInputs = with ocamlPackages; [ 7 | nodejs_latest 8 | yarn 9 | merlin 10 | melange 11 | reason 12 | python3 13 | # ocamlformat 14 | dune 15 | ocaml 16 | findlib 17 | dot-merlin-reader 18 | # merlin 19 | ]; 20 | 21 | inputsFrom = [ (pkgs.callPackage ./nix { }).native ]; 22 | 23 | BSB_PATH = "/Users/anmonteiro/projects/melange"; 24 | shellHook = '' 25 | PATH=$BSB_PATH/bin:$PATH 26 | ''; 27 | } 28 | -------------------------------------------------------------------------------- /src/palette.scss: -------------------------------------------------------------------------------- 1 | /* Coolors Exported Palette - coolors.co/26547c-bac1b8-f8fff4-ed6a5a-f4f1bb */ 2 | 3 | /* HSL */ 4 | $blue: hsla(208%, 53%, 32%, 1); 5 | $gray: hsla(107%, 7%, 74%, 1); 6 | $cream: hsla(98%, 100%, 98%, 1); 7 | $red: hsla(7%, 80%, 64%, 1); 8 | $blond: hsla(57%, 72%, 85%, 1); 9 | $baby: hsla(60%, 100%, 99%, 1); 10 | 11 | /* RGB */ 12 | $blue: rgba(38, 84, 124, 1); 13 | $gray: rgba(186, 193, 184, 1); 14 | $cream: rgba(248, 255, 244, 1); 15 | $red: rgba(237, 106, 90, 1); 16 | $blond: rgba(244, 241, 187, 1); 17 | $baby: rgba(255, 255, 250, 1); 18 | -------------------------------------------------------------------------------- /src/request.ml: -------------------------------------------------------------------------------- 1 | open Let_syntax.Bindings 2 | 3 | external js_error_message : Js.Promise.error -> string = "message" [@@bs.get] 4 | 5 | let request_json endpoint = 6 | let+ response = 7 | Bs_fetch.( 8 | fetchWithInit 9 | endpoint 10 | (RequestInit.make 11 | ~mode:CORS 12 | ~headers: 13 | (HeadersInit.makeWithArray [| "accept", "application/json" |]) 14 | ())) 15 | |> Js.Promise.then_ Bs_fetch.Response.json 16 | |. Promise.Js.fromBsPromise 17 | |. Promise.Js.toResult 18 | in 19 | match response with Ok r -> Ok r | Error msg -> Error (js_error_message msg) 20 | -------------------------------------------------------------------------------- /esy.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "bs-platform": "*", 4 | "@opam/merlin": "*" 5 | }, 6 | "resolutions": { 7 | "bs-platform": "EduardoRFS/bucklescript#97d478aa2f72ac92b776dfc9a50f316f6a46eefa", 8 | "ocaml": "anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb" 9 | }, 10 | "esy": { 11 | "buildsInSource": "_build", 12 | "build": [ 13 | "ln -sfn #{bs-platform.install} node_modules/bs-platform", 14 | "sh -c \"echo '(lang dune 2.7)' > node_modules/bs-decoders/dune-project\"", 15 | "bsb -clean-world -make-world" 16 | ] 17 | }, 18 | "installConfig": { 19 | "pnp": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Piaf Nix Flake"; 3 | 4 | inputs.flake-utils.url = "github:numtide/flake-utils"; 5 | inputs.nixpkgs.url = "github:anmonteiro/nix-overlays"; 6 | 7 | outputs = { self, nixpkgs, flake-utils }: 8 | flake-utils.lib.eachDefaultSystem (system: 9 | let 10 | pkgs = nixpkgs.legacyPackages.${system}.extend (self: super: { 11 | ocamlPackages = super.ocaml-ng.ocamlPackages_4_14; 12 | }); 13 | in 14 | rec { 15 | packages = pkgs.callPackage ./nix { inherit pkgs; }; 16 | defaultPackage = packages.native; 17 | devShell = import ./shell.nix { inherit pkgs; }; 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /src/index.scss: -------------------------------------------------------------------------------- 1 | @import "~normalize.css"; 2 | @import "./palette.scss"; 3 | 4 | body { 5 | background-color: $cream; 6 | margin: 0; 7 | padding: 0; 8 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 9 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | } 14 | 15 | code { 16 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 17 | monospace; 18 | } 19 | 20 | a { 21 | color: $blue; 22 | } 23 | 24 | *, 25 | *:before, 26 | *:after { 27 | box-sizing: border-box; 28 | -moz-box-sizing: border-box; 29 | -webkit-box-sizing: border-box; 30 | -ms-box-sizing: border-box; 31 | } 32 | -------------------------------------------------------------------------------- /esy.lock/opam/conf-m4.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "tim@gfxmonk.net" 3 | homepage: "http://www.gnu.org/software/m4/m4.html" 4 | bug-reports: "https://github.com/ocaml/opam-repository/issues" 5 | authors: "GNU Project" 6 | license: "GPL-3.0-only" 7 | build: [["sh" "-exc" "echo | m4"]] 8 | depexts: [ 9 | ["m4"] {os-family = "debian"} 10 | ["m4"] {os-distribution = "fedora"} 11 | ["m4"] {os-distribution = "rhel"} 12 | ["m4"] {os-distribution = "centos"} 13 | ["m4"] {os-distribution = "alpine"} 14 | ["m4"] {os-distribution = "nixos"} 15 | ["m4"] {os-family = "suse"} 16 | ["m4"] {os-distribution = "ol"} 17 | ["m4"] {os-distribution = "arch"} 18 | ] 19 | synopsis: "Virtual package relying on m4" 20 | description: 21 | "This package can only install if the m4 binary is installed on the system." 22 | flags: conf 23 | -------------------------------------------------------------------------------- /.ocamlformat: -------------------------------------------------------------------------------- 1 | break-infix = fit-or-vertical 2 | break-infix-before-func = false 3 | break-fun-decl = fit-or-vertical 4 | break-separators = before 5 | break-sequences = true 6 | cases-exp-indent = 2 7 | dock-collection-brackets = false 8 | field-space = loose 9 | if-then-else = keyword-first 10 | indicate-multiline-delimiters = no 11 | infix-precedence = parens 12 | leading-nested-match-parens = true 13 | let-and = sparse 14 | let-module = sparse 15 | ocp-indent-compat = true 16 | parens-tuple = multi-line-only 17 | parse-docstrings = true 18 | sequence-blank-line = preserve-one 19 | sequence-style = terminator 20 | single-case = sparse 21 | space-around-arrays= true 22 | space-around-lists= true 23 | space-around-records= true 24 | space-around-variants= true 25 | type-decl = sparse 26 | wrap-comments = true 27 | wrap-fun-args = false 28 | 29 | -------------------------------------------------------------------------------- /esy.lock/opam/fix.20201120/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | ] 6 | homepage: "https://gitlab.inria.fr/fpottier/fix" 7 | dev-repo: "git+https://gitlab.inria.fr/fpottier/fix.git" 8 | bug-reports: "francois.pottier@inria.fr" 9 | build: [ 10 | ["dune" "build" "-p" name "-j" jobs] 11 | ] 12 | depends: [ 13 | "ocaml" { >= "4.03" } 14 | "dune" {>= "1.3" } 15 | ] 16 | synopsis: "Facilities for memoization and fixed points" 17 | url { 18 | src: 19 | "https://gitlab.inria.fr/fpottier/fix/repository/20201120/archive.tar.gz" 20 | checksum: [ 21 | "md5=7eb570b759635fe66f3556d2b1cc88e3" 22 | "sha512=344dcc619f9e8b8a6c998775b6d2dab2ea5253e6a67abe4797f76dc5dd30bc776568abce1e90477422e9db447821579889737e3531c42139708f813e983ea5d4" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /nix/ci.nix: -------------------------------------------------------------------------------- 1 | { ocamlVersion ? "4_12" }: 2 | 3 | let 4 | lock = builtins.fromJSON (builtins.readFile ./../flake.lock); 5 | src = fetchGit { 6 | url = with lock.nodes.nixpkgs.locked;"https://github.com/${owner}/${repo}"; 7 | inherit (lock.nodes.nixpkgs.locked) rev; 8 | # inherit (lock.nodes.nixpkgs.original) ref; 9 | }; 10 | pkgs = import "${src}/boot.nix" { 11 | overlays = [ 12 | (import src) 13 | (self: super: { 14 | ocamlPackages = super.ocaml-ng."ocamlPackages_${ocamlVersion}"; 15 | 16 | pkgsCross.musl64 = super.pkgsCross.musl64 // { 17 | ocamlPackages = super.pkgsCross.musl64.ocaml-ng."ocamlPackages_${ocamlVersion}"; 18 | }; 19 | }) 20 | ]; 21 | }; 22 | 23 | inherit (pkgs) lib stdenv fetchTarball ocamlPackages; 24 | 25 | in 26 | 27 | (pkgs.callPackage ./. { }).musl64 28 | -------------------------------------------------------------------------------- /src/Ui.module.scss: -------------------------------------------------------------------------------- 1 | @import "./palette.scss"; 2 | @import "./units.scss"; 3 | 4 | .card { 5 | position: relative; 6 | display: flex; 7 | background-color: $baby; 8 | border-radius: 8px; 9 | box-shadow: 0 $xs $xs 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 10 | margin-bottom: $s; 11 | transition: all 0.3s; 12 | } 13 | 14 | .card::after { 15 | content: " "; 16 | position: absolute; 17 | border-radius: 8px; 18 | z-index: -1; 19 | top: 0; 20 | left: 0; 21 | width: 100%; 22 | height: 100%; 23 | box-shadow: 0 $xs $s 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 24 | opacity: 0; 25 | transition: opacity 0.3s; 26 | } 27 | 28 | .card:hover { 29 | margin-bottom: $m; 30 | transform: scale(1.01); 31 | } 32 | 33 | .card:hover::after { 34 | opacity: 1; 35 | } 36 | 37 | .cardInner { 38 | margin: 20px; 39 | } 40 | -------------------------------------------------------------------------------- /esy.lock/opam/ppx_derivers.1.2.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "jeremie@dimino.org" 3 | authors: ["Jérémie Dimino"] 4 | license: "BSD-3-Clause" 5 | homepage: "https://github.com/ocaml-ppx/ppx_derivers" 6 | bug-reports: "https://github.com/ocaml-ppx/ppx_derivers/issues" 7 | dev-repo: "git://github.com/ocaml-ppx/ppx_derivers.git" 8 | build: [ 9 | ["dune" "build" "-p" name "-j" jobs] 10 | ] 11 | depends: [ 12 | "ocaml" 13 | "dune" 14 | ] 15 | synopsis: "Shared [@@deriving] plugin registry" 16 | description: """ 17 | Ppx_derivers is a tiny package whose sole purpose is to allow 18 | ppx_deriving and ppx_type_conv to inter-operate gracefully when linked 19 | as part of the same ocaml-migrate-parsetree driver.""" 20 | url { 21 | src: "https://github.com/ocaml-ppx/ppx_derivers/archive/1.2.1.tar.gz" 22 | checksum: "md5=5dc2bf130c1db3c731fe0fffc5648b41" 23 | } 24 | -------------------------------------------------------------------------------- /esy.lock/opam/result.1.5/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "opensource@janestreet.com" 3 | authors: ["Jane Street Group, LLC "] 4 | homepage: "https://github.com/janestreet/result" 5 | dev-repo: "git+https://github.com/janestreet/result.git" 6 | bug-reports: "https://github.com/janestreet/result/issues" 7 | license: "BSD-3-Clause" 8 | build: [["dune" "build" "-p" name "-j" jobs]] 9 | depends: [ 10 | "ocaml" 11 | "dune" {>= "1.0"} 12 | ] 13 | synopsis: "Compatibility Result module" 14 | description: """ 15 | Projects that want to use the new result type defined in OCaml >= 4.03 16 | while staying compatible with older version of OCaml should use the 17 | Result module defined in this library.""" 18 | url { 19 | src: 20 | "https://github.com/janestreet/result/releases/download/1.5/result-1.5.tbz" 21 | checksum: "md5=1b82dec78849680b49ae9a8a365b831b" 22 | } 23 | -------------------------------------------------------------------------------- /shared/feed.ml: -------------------------------------------------------------------------------- 1 | module Author = struct 2 | type t = 3 | { name : string 4 | ; uri : string option 5 | ; email : string option 6 | } 7 | [@@deriving yojson] 8 | end 9 | 10 | module Link = struct 11 | type t = 12 | { title : string 13 | ; href : string 14 | } 15 | [@@deriving yojson] 16 | end 17 | 18 | module Entry = struct 19 | type t = 20 | { authors : Author.t * Author.t list 21 | ; content : string option 22 | ; id : string 23 | ; links : Link.t list 24 | ; published : float option 25 | ; title : string 26 | ; updated : float 27 | } 28 | [@@deriving yojson] 29 | end 30 | 31 | type t = 32 | { authors : Author.t list 33 | ; id : string 34 | ; links : Link.t list 35 | ; logo : string option 36 | ; subtitle : string option 37 | ; title : string 38 | ; updated : float 39 | ; entries : Entry.t list 40 | } 41 | [@@deriving yojson] 42 | -------------------------------------------------------------------------------- /nix/generic.nix: -------------------------------------------------------------------------------- 1 | { filterGitSource, stdenv, openssl, ocamlPackages, static ? false }: 2 | 3 | stdenv.mkDerivation { 4 | name = "gh-feed-lambda"; 5 | version = "dev"; 6 | 7 | src = filterGitSource { 8 | src = ./..; 9 | dirs = [ "lambda" "shared" ]; 10 | files = [ "dune-project" ]; 11 | }; 12 | 13 | nativeBuildInputs = with ocamlPackages; [ dune_2 ocaml findlib ]; 14 | 15 | buildPhase = '' 16 | echo "running ${if static then "static" else "release"} build" 17 | dune build lambda/lambda.exe --display=short --profile=${if static then "static" else "release"} 18 | ''; 19 | installPhase = '' 20 | mkdir -p $out/bin 21 | mv _build/default/lambda/lambda.exe $out/bin/lambda.exe 22 | ''; 23 | 24 | buildInputs = with ocamlPackages; [ 25 | piaf 26 | lambdasoup 27 | ppx_deriving_yojson 28 | syndic 29 | lwt 30 | fmt 31 | vercel 32 | ]; 33 | 34 | doCheck = false; 35 | } 36 | -------------------------------------------------------------------------------- /esy.lock/opam/menhir.20210310/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | "Yann Régis-Gianas " 6 | ] 7 | homepage: "http://gitlab.inria.fr/fpottier/menhir" 8 | dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git" 9 | bug-reports: "menhir@inria.fr" 10 | build: [ 11 | ["dune" "build" "-p" name "-j" jobs] 12 | ] 13 | depends: [ 14 | "ocaml" {>= "4.02.3"} 15 | "dune" { >= "2.2.0"} 16 | "menhirLib" {= version} 17 | "menhirSdk" {= version} 18 | ] 19 | synopsis: "An LR(1) parser generator" 20 | url { 21 | src: 22 | "https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz" 23 | checksum: [ 24 | "md5=1cbc71c0bc1f3ddc3e71d5c1f919fd1a" 25 | "sha512=3c309fa2cc4ad7c6fba85107bd946a542894882fa39741496b150307e93455b717418f19e94b5dad06ab269f5c55e8dc25705c96c0a5092e623fa38f1ce43c7f" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /esy.lock/opam/menhirLib.20210310/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | "Yann Régis-Gianas " 6 | ] 7 | homepage: "http://gitlab.inria.fr/fpottier/menhir" 8 | dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git" 9 | bug-reports: "menhir@inria.fr" 10 | build: [ 11 | ["dune" "build" "-p" name "-j" jobs] 12 | ] 13 | depends: [ 14 | "ocaml" { >= "4.02.3" } 15 | "dune" { >= "2.0.0" } 16 | ] 17 | conflicts: [ 18 | "menhir" { != version } 19 | ] 20 | synopsis: "Runtime support library for parsers generated by Menhir" 21 | url { 22 | src: 23 | "https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz" 24 | checksum: [ 25 | "md5=1cbc71c0bc1f3ddc3e71d5c1f919fd1a" 26 | "sha512=3c309fa2cc4ad7c6fba85107bd946a542894882fa39741496b150307e93455b717418f19e94b5dad06ab269f5c55e8dc25705c96c0a5092e623fa38f1ce43c7f" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /esy.lock/opam/menhirSdk.20210310/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | "Yann Régis-Gianas " 6 | ] 7 | homepage: "http://gitlab.inria.fr/fpottier/menhir" 8 | dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git" 9 | bug-reports: "menhir@inria.fr" 10 | build: [ 11 | ["dune" "build" "-p" name "-j" jobs] 12 | ] 13 | depends: [ 14 | "ocaml" { >= "4.02.3" } 15 | "dune" { >= "2.0.0" } 16 | ] 17 | conflicts: [ 18 | "menhir" { != version } 19 | ] 20 | synopsis: "Compile-time library for auxiliary tools related to Menhir" 21 | url { 22 | src: 23 | "https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz" 24 | checksum: [ 25 | "md5=1cbc71c0bc1f3ddc3e71d5c1f919fd1a" 26 | "sha512=3c309fa2cc4ad7c6fba85107bd946a542894882fa39741496b150307e93455b717418f19e94b5dad06ab269f5c55e8dc25705c96c0a5092e623fa38f1ce43c7f" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src/api.re: -------------------------------------------------------------------------------- 1 | let parseFeed = payload => 2 | switch (Decoders_bs.Decode.decode_value(Decode_feed.decode_feed, payload)) { 3 | | Ok(data) => Ok(data) 4 | | Error(e) => Error(Format.asprintf("%a", Decoders_bs.Decode.pp_error, e)) 5 | }; 6 | 7 | let feedEndpoint = (~token=?, ~page, user) => { 8 | let endpoint = {j|https://gh-feed.now.sh/api?user=$(user)&page=$(page)|j}; 9 | switch (token) { 10 | | None => endpoint 11 | | Some(token) => {j|$(endpoint)&token=$(token)|j} 12 | }; 13 | }; 14 | 15 | let fetcher = endpoint => { 16 | let p_result = Request.request_json(endpoint); 17 | Promise.map(p_result, r => Belt.Result.flatMap(r, parseFeed)); 18 | }; 19 | 20 | module SWR = { 21 | module SWRConfig = { 22 | [@bs.module "swr"] [@react.component] 23 | external make: 24 | (~value: Js.t({..}), ~children: React.element) => React.element = 25 | "SWRConfig"; 26 | }; 27 | 28 | type t('data, 'error) = { 29 | data: option('data), 30 | error: option('error), 31 | }; 32 | 33 | [@bs.module "swr"] external useSWR: string => t('data, 'error) = "default"; 34 | }; 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Antonio Nuno Monteiro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /esy.lock/opam/dot-merlin-reader.4.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "defree@gmail.com" 3 | authors: "The Merlin team" 4 | synopsis: "Reads config files for merlin" 5 | homepage: "https://github.com/ocaml/merlin" 6 | bug-reports: "https://github.com/ocaml/merlin/issues" 7 | dev-repo: "git+https://github.com/ocaml/merlin.git" 8 | build: [ 9 | ["dune" "subst"] {pinned} 10 | ["dune" "build" "-p" name "-j" jobs] 11 | ] 12 | depends: [ 13 | "ocaml" {>= "4.06.1" } 14 | "dune" {>= "2.7.0"} 15 | "yojson" {>= "1.6.0"} 16 | "ocamlfind" {>= "1.6.0"} 17 | "csexp" {>= "1.2.3"} 18 | "result" {>= "1.5"} 19 | ] 20 | description: 21 | "Helper process: reads .merlin files and gives the normalized content to merlin" 22 | x-commit-hash: "ab02f60994c81166820791b5f465f467d752b8dc" 23 | url { 24 | src: 25 | "https://github.com/ocaml/merlin/releases/download/v4.1/dot-merlin-reader-v4.1.tbz" 26 | checksum: [ 27 | "sha256=14a36d6fb8646a5df4530420a7861722f1a4ee04753717947305e3676031e7cd" 28 | "sha512=65fd4ab08904c05651a7ef8971802ffaa428daa920765dbcf162e3c56e8047e4c9e4356daa45efccce7c73a586635c8f6cf8118fd3059789de9aff68579bd436" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /esy.lock/overrides/opam__s__ocamlfind_opam__c__1.8.1_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "bash", 5 | "-c", 6 | "#{os == 'windows' ? 'patch -p1 < findlib-1.8.1.patch' : 'true'}" 7 | ], 8 | [ 9 | "./configure", 10 | "-bindir", 11 | "#{self.bin}", 12 | "-sitelib", 13 | "#{self.lib}", 14 | "-mandir", 15 | "#{self.man}", 16 | "-config", 17 | "#{self.lib}/findlib.conf", 18 | "-no-custom", 19 | "-no-topfind" 20 | ], 21 | [ 22 | "make", 23 | "all" 24 | ], 25 | [ 26 | "make", 27 | "opt" 28 | ] 29 | ], 30 | "install": [ 31 | [ 32 | "make", 33 | "install" 34 | ], 35 | [ 36 | "install", 37 | "-m", 38 | "0755", 39 | "ocaml-stub", 40 | "#{self.bin}/ocaml" 41 | ], 42 | [ 43 | "mkdir", 44 | "-p", 45 | "#{self.toplevel}" 46 | ], 47 | [ 48 | "install", 49 | "-m", 50 | "0644", 51 | "src/findlib/topfind", 52 | "#{self.toplevel}/topfind" 53 | ] 54 | ], 55 | "exportedEnv": { 56 | "OCAML_TOPLEVEL_PATH": { 57 | "val": "#{self.toplevel}", 58 | "scope": "global" 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /esy.lock/opam/merlin-extend.0.6/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Frederic Bour " 3 | authors: "Frederic Bour " 4 | homepage: "https://github.com/let-def/merlin-extend" 5 | bug-reports: "https://github.com/let-def/merlin-extend" 6 | license: "MIT" 7 | dev-repo: "git+https://github.com/let-def/merlin-extend.git" 8 | build: [ 9 | ["dune" "subst"] {pinned} 10 | ["dune" "build" "-p" name "-j" jobs] 11 | ] 12 | depends: [ 13 | "dune" {>= "1.0"} 14 | "cppo" {build} 15 | "ocaml" {>= "4.02.3"} 16 | ] 17 | synopsis: "A protocol to provide custom frontend to Merlin" 18 | description: """ 19 | This protocol allows to replace the OCaml frontend of Merlin. 20 | It extends what used to be done with the `-pp' flag to handle a few more cases.""" 21 | doc: "https://let-def.github.io/merlin-extend" 22 | x-commit-hash: "640620568a5f5c7798239ecf7c707c813e3df3cf" 23 | url { 24 | src: 25 | "https://github.com/let-def/merlin-extend/releases/download/v0.6/merlin-extend-v0.6.tbz" 26 | checksum: [ 27 | "sha256=c2f236ae97feb6ba0bc90f33beb7b7343e42f9871b66de9ba07974917e256c43" 28 | "sha512=4c64a490e2ece04fc89aef679c1d9202175df4fe045b5fdc7a37cd7cebe861226fddd9648c1bf4f06175ecfcd2ed7686c96bd6a8cae003a5096f6134c240f857" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gh-feed", 3 | "alias": "gh.an.wtf", 4 | "version": 2, 5 | "regions": [ 6 | "sfo1" 7 | ], 8 | "builds": [ 9 | { 10 | "src": "+(bootstrap|cacert.pem)", 11 | "use": "now-custom-runtime" 12 | }, 13 | { 14 | "src": "package.json", 15 | "use": "@now/static-build", 16 | "config": { 17 | "distDir": "build" 18 | } 19 | } 20 | ], 21 | "routes": [ 22 | { 23 | "src": "/api", 24 | "dest": "/bootstrap", 25 | "headers": { 26 | "cache-control": "s-maxage=180", 27 | "access-control-allow-origin": "*" 28 | } 29 | }, 30 | { 31 | "src": "/favicon.ico", 32 | "dest": "/favicon.ico" 33 | }, 34 | { 35 | "src": "/asset-manifest.json", 36 | "dest": "/asset-manifest.json" 37 | }, 38 | { 39 | "src": "/manifest.json", 40 | "dest": "/manifest.json" 41 | }, 42 | { 43 | "src": "/precache-manifest.(.*)", 44 | "dest": "/precache-manifest.$1" 45 | }, 46 | { 47 | "src": "/static/(.*)", 48 | "dest": "/static/$1", 49 | "headers": { 50 | "cache-control": "s-maxage=31536000,immutable" 51 | } 52 | }, 53 | { 54 | "src": "/.*", 55 | "dest": "/index.html" 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /src/let_syntax.ml: -------------------------------------------------------------------------------- 1 | open Belt 2 | 3 | module Async = struct 4 | let ( let+ ) = Promise.map 5 | 6 | let ( let* ) = Promise.flatMap 7 | 8 | let ( and* ) a b = Promise.all2 a b 9 | end 10 | 11 | module Option = struct 12 | let ( let+ ) = Option.map 13 | 14 | let ( let* ) = Option.flatMap 15 | 16 | let ( and* ) o1 o2 = 17 | match o1, o2 with Some x, Some y -> Some (x, y) | _ -> None 18 | end 19 | 20 | module Result = struct 21 | let ( let+ ) = Result.map 22 | 23 | let ( let* ) = Result.flatMap 24 | 25 | let ( and* ) r1 r2 = 26 | match r1, r2 with 27 | | Ok x, Ok y -> 28 | Ok (x, y) 29 | | Ok _, Error e | Error e, Ok _ | Error e, Error _ -> 30 | Error e 31 | end 32 | 33 | module Bindings = struct 34 | include Async 35 | 36 | let ( let*? ) = Option.( let* ) 37 | 38 | let ( let+? ) = Option.( let+ ) 39 | 40 | let ( and*? ) = Option.( and* ) 41 | 42 | let ( let*! ) = Result.( let* ) 43 | 44 | let ( let+! ) = Result.( let+ ) 45 | 46 | let ( and*! ) = Result.( and* ) 47 | 48 | let ( let**! ) = Promise.flatMapOk 49 | 50 | let ( let++! ) = Promise.mapOk 51 | 52 | let ( and**! ) lr1 lr2 = 53 | Promise.all2 lr1 lr2 54 | |. Promise.map (function 55 | | Ok x, Ok y -> 56 | Ok (x, y) 57 | | Ok _, Error e | Error e, Ok _ | Error e, Error _ -> 58 | Error e) 59 | end 60 | -------------------------------------------------------------------------------- /esy.lock/opam/yojson.1.7.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: ["Martin Jambon"] 4 | homepage: "https://github.com/ocaml-community/yojson" 5 | bug-reports: "https://github.com/ocaml-community/yojson/issues" 6 | dev-repo: "git+https://github.com/ocaml-community/yojson.git" 7 | doc: "https://ocaml-community.github.io/yojson/" 8 | build: [ 9 | ["dune" "subst"] {pinned} 10 | ["dune" "build" "-p" name "-j" jobs] 11 | ] 12 | run-test: [["dune" "runtest" "-p" name "-j" jobs]] 13 | depends: [ 14 | "ocaml" {>= "4.02.3"} 15 | "dune" 16 | "cppo" {build} 17 | "easy-format" 18 | "biniou" {>= "1.2.0"} 19 | "alcotest" {with-test & >= "0.8.5"} 20 | ] 21 | synopsis: 22 | "Yojson is an optimized parsing and printing library for the JSON format" 23 | description: """ 24 | Yojson is an optimized parsing and printing library for the JSON format. 25 | 26 | It addresses a few shortcomings of json-wheel including 2x speedup, 27 | polymorphic variants and optional syntax for tuples and variants. 28 | 29 | ydump is a pretty-printing command-line program provided with the 30 | yojson package. 31 | 32 | The program atdgen can be used to derive OCaml-JSON serializers and 33 | deserializers from type definitions.""" 34 | url { 35 | src: 36 | "https://github.com/ocaml-community/yojson/releases/download/1.7.0/yojson-1.7.0.tbz" 37 | checksum: "md5=b89d39ca3f8c532abe5f547ad3b8f84d" 38 | } 39 | -------------------------------------------------------------------------------- /esy.lock/opam/cppo.1.6.7/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: "Martin Jambon" 4 | license: "BSD-3-Clause" 5 | homepage: "https://github.com/ocaml-community/cppo" 6 | doc: "https://ocaml-community.github.io/cppo/" 7 | bug-reports: "https://github.com/ocaml-community/cppo/issues" 8 | depends: [ 9 | "ocaml" {>= "4.02.3"} 10 | "dune" {>= "1.0"} 11 | "base-unix" 12 | ] 13 | build: [ 14 | ["dune" "subst"] {pinned} 15 | ["dune" "build" "-p" name "-j" jobs] 16 | ["dune" "runtest" "-p" name "-j" jobs] {with-test} 17 | ] 18 | dev-repo: "git+https://github.com/ocaml-community/cppo.git" 19 | synopsis: "Code preprocessor like cpp for OCaml" 20 | description: """ 21 | Cppo is an equivalent of the C preprocessor for OCaml programs. 22 | It allows the definition of simple macros and file inclusion. 23 | 24 | Cppo is: 25 | 26 | * more OCaml-friendly than cpp 27 | * easy to learn without consulting a manual 28 | * reasonably fast 29 | * simple to install and to maintain 30 | """ 31 | x-commit-hash: "7d217864a5fdc4551699e248137a2f8b719d2078" 32 | url { 33 | src: 34 | "https://github.com/ocaml-community/cppo/releases/download/v1.6.7/cppo-v1.6.7.tbz" 35 | checksum: [ 36 | "sha256=db553e3e6c206df09b1858c3aef5e21e56564d593642a3c78bcedb6af36f529d" 37 | "sha512=9722b50fd23aaccf86816313333a3bf8fc7c6b4ef06b153e5e1e1aaf14670cf51a4aac52fb1b4a0e5531699c4047a1eff6c24c969f7e5063e78096c2195b5819" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gh-feed", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@primer/css": "^15.0.0", 7 | "@rescript/react": "^0.10.3", 8 | "bs-decoders": "^0.3.0", 9 | "bs-fetch": "^0.6.2", 10 | "cra-reason-template": "^0.1.3", 11 | "github-syntax-light": "^0.5.0", 12 | "normalize.css": "^8.0.1", 13 | "react": "experimental", 14 | "reason-promise": "^1.0.0", 15 | "swr": "^0.3.0" 16 | }, 17 | "scripts": { 18 | "start": "FORCE_COLOR=true react-scripts start | cat -n", 19 | "build-cra": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject", 22 | "bs:make": "bsb.exe -make-world", 23 | "bs:watch": "bsb.exe -make-world -w", 24 | "bs:clean": "bsb.exe -clean-world", 25 | "now-build": "yarn add bs-platform@7.3.1 && yarn bs:clean && yarn bs:make && yarn build-cra" 26 | }, 27 | "eslintConfig": { 28 | "extends": "react-app" 29 | }, 30 | "resolutions": { 31 | "reason-react/**/react": "0.0.0-experimental-94c0244ba", 32 | "reason-react/**/react-dom": "0.0.0-experimental-94c0244ba", 33 | "react": "0.0.0-experimental-79ed5e18f-20220217", 34 | "react-dom": "0.0.0-experimental-79ed5e18f-20220217" 35 | }, 36 | "browserslist": [ 37 | ">0.2%", 38 | "not dead", 39 | "not ie <= 11", 40 | "not op_mini all" 41 | ], 42 | "devDependencies": { 43 | "prettier": "^2.0.5" 44 | }, 45 | "installConfig": { 46 | "pnp": false 47 | }, 48 | "engines": { 49 | "node": ">=10.0.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # start from node image so we can install esy from npm 2 | FROM node:12-alpine as build 3 | 4 | ENV TERM=dumb LD_LIBRARY_PATH=/usr/local/lib:/usr/lib:/lib 5 | 6 | RUN mkdir /esy 7 | WORKDIR /esy 8 | 9 | ENV NPM_CONFIG_PREFIX=/esy 10 | RUN npm install -g --unsafe-perm @esy-nightly/esy 11 | 12 | # now that we have esy installed we need a proper runtime 13 | 14 | FROM alpine:3.8 as esy 15 | 16 | ENV TERM=dumb LD_LIBRARY_PATH=/usr/local/lib:/usr/lib:/lib 17 | 18 | WORKDIR / 19 | 20 | COPY --from=build /esy /esy 21 | 22 | RUN apk add --no-cache ca-certificates wget bash curl perl-utils git patch \ 23 | gcc g++ musl-dev make m4 linux-headers coreutils 24 | 25 | RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub 26 | RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk 27 | RUN apk add --no-cache glibc-2.28-r0.apk 28 | 29 | ENV PATH=/esy/bin:$PATH 30 | 31 | RUN mkdir /app 32 | WORKDIR /app 33 | 34 | RUN echo ' \ 35 | {\ 36 | "name": "package-base", \ 37 | "dependencies": { \ 38 | "ocaml": "~4.9.0", \ 39 | "@opam/dune": ">= 2.0.0", \ 40 | "@opam/conf-libssl": "*" \ 41 | }, \ 42 | "resolutions": { \ 43 | "@opam/conf-libssl": "esy-packages/esy-openssl#77c1dbe" \ 44 | } \ 45 | } \ 46 | ' > esy.json 47 | 48 | RUN esy 49 | 50 | COPY esy.json esy.json 51 | COPY esy.lock esy.lock 52 | 53 | RUN esy fetch 54 | RUN esy true 55 | 56 | COPY . . 57 | 58 | RUN esy b dune build lambda/lambda.exe --profile=static 59 | 60 | RUN mv $(esy echo '#{self.target_dir}')/default/lambda/lambda.exe bootstrap 61 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 |
27 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/decode_feed.ml: -------------------------------------------------------------------------------- 1 | module D = Decoders_bs.Decode 2 | open Feed 3 | open D.Infix 4 | 5 | let x = D.( >>= ) 6 | 7 | let decode_author = 8 | D.(field "name" string) >>= fun name -> 9 | D.(maybe (field "uri" string)) >>= fun uri -> 10 | D.(maybe (field "email" string)) >>= fun email -> 11 | D.succeed { Author.name; email; uri } 12 | 13 | let decode_link = 14 | D.(field "title" string) >>= fun title -> 15 | D.(field "href" string) >>= fun href -> D.succeed { Link.title; href } 16 | 17 | let decode_entry = 18 | let decode_authors_field : (Author.t * Author.t list) D.decoder = 19 | D.index 0 decode_author >>= fun author -> 20 | D.(index 1 (list decode_author)) >>= fun authors -> 21 | D.succeed (author, authors) 22 | in 23 | D.(field "authors" decode_authors_field) >>= fun authors -> 24 | D.(maybe (field "content" string)) >>= fun content -> 25 | D.(field "id" string) >>= fun id -> 26 | D.(field "links" (list decode_link)) >>= fun links -> 27 | D.(maybe (field "published" float)) >>= fun published -> 28 | D.(field "title" string) >>= fun title -> 29 | D.(field "updated" float) >>= fun updated -> 30 | D.succeed { Entry.authors; content; id; links; published; title; updated } 31 | 32 | let decode_feed = 33 | D.(field "authors" (list decode_author)) >>= fun authors -> 34 | D.(field "id" string) >>= fun id -> 35 | D.(field "links" (list decode_link)) >>= fun links -> 36 | D.(maybe (field "logo" string)) >>= fun logo -> 37 | D.(maybe (field "subtitle" string)) >>= fun subtitle -> 38 | D.(field "title" string) >>= fun title -> 39 | D.(field "updated" float) >>= fun updated -> 40 | D.(field "entries" (list decode_entry)) >>= fun entries -> 41 | D.succeed { authors; id; links; logo; subtitle; title; updated; entries } 42 | -------------------------------------------------------------------------------- /esy.lock/opam/easy-format.1.3.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | build: [ 3 | ["dune" "subst"] {pinned} 4 | ["dune" "build" "-p" name "-j" jobs] 5 | ["dune" "runtest" "-p" name "-j" jobs] {with-test} 6 | ["dune" "build" "-p" name "@doc"] {with-doc} 7 | ] 8 | maintainer: ["martin@mjambon.com" "rudi.grinberg@gmail.com"] 9 | authors: ["Martin Jambon"] 10 | bug-reports: "https://github.com/mjambon/easy-format/issues" 11 | homepage: "https://github.com/mjambon/easy-format" 12 | doc: "https://mjambon.github.io/easy-format/" 13 | license: "BSD-3-Clause" 14 | dev-repo: "git+https://github.com/mjambon/easy-format.git" 15 | synopsis: 16 | "High-level and functional interface to the Format module of the OCaml standard library" 17 | description: """ 18 | 19 | This module offers a high-level and functional interface to the Format module of 20 | the OCaml standard library. It is a pretty-printing facility, i.e. it takes as 21 | input some code represented as a tree and formats this code into the most 22 | visually satisfying result, breaking and indenting lines of code where 23 | appropriate. 24 | 25 | Input data must be first modelled and converted into a tree using 3 kinds of 26 | nodes: 27 | 28 | * atoms 29 | * lists 30 | * labelled nodes 31 | 32 | Atoms represent any text that is guaranteed to be printed as-is. Lists can model 33 | any sequence of items such as arrays of data or lists of definitions that are 34 | labelled with something like "int main", "let x =" or "x:".""" 35 | depends: [ 36 | "dune" {>= "1.10"} 37 | "ocaml" {>= "4.02.3"} 38 | ] 39 | url { 40 | src: 41 | "https://github.com/mjambon/easy-format/releases/download/1.3.2/easy-format-1.3.2.tbz" 42 | checksum: [ 43 | "sha256=3440c2b882d537ae5e9011eb06abb53f5667e651ea4bb3b460ea8230fa8c1926" 44 | "sha512=e39377a2ff020ceb9ac29e8515a89d9bdbc91dfcfa871c4e3baafa56753fac2896768e5d9822a050dc1e2ade43c8967afb69391a386c0a8ecd4e1f774e236135" 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /esy.lock/opam/biniou.1.2.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | build: [ 3 | ["dune" "subst"] {pinned} 4 | ["dune" "build" "-p" name "-j" jobs] 5 | ["dune" "runtest" "-p" name "-j" jobs] {with-test} 6 | ["dune" "build" "-p" name "@doc"] {with-doc} 7 | ] 8 | maintainer: ["martin@mjambon.com"] 9 | authors: ["Martin Jambon"] 10 | bug-reports: "https://github.com/mjambon/biniou/issues" 11 | homepage: "https://github.com/mjambon/biniou" 12 | doc: "https://mjambon.github.io/biniou/" 13 | license: "BSD-3-Clause" 14 | dev-repo: "git+https://github.com/mjambon/biniou.git" 15 | synopsis: 16 | "Binary data format designed for speed, safety, ease of use and backward compatibility as protocols evolve" 17 | description: """ 18 | 19 | Biniou (pronounced "be new") is a binary data format designed for speed, safety, 20 | ease of use and backward compatibility as protocols evolve. Biniou is vastly 21 | equivalent to JSON in terms of functionality but allows implementations several 22 | times faster (4 times faster than yojson), with 25-35% space savings. 23 | 24 | Biniou data can be decoded into human-readable form without knowledge of type 25 | definitions except for field and variant names which are represented by 31-bit 26 | hashes. A program named bdump is provided for routine visualization of biniou 27 | data files. 28 | 29 | The program atdgen is used to derive OCaml-Biniou serializers and deserializers 30 | from type definitions. 31 | 32 | Biniou format specification: mjambon.github.io/atdgen-doc/biniou-format.txt""" 33 | depends: [ 34 | "easy-format" 35 | "dune" {>= "1.10"} 36 | "ocaml" {>= "4.02.3"} 37 | ] 38 | url { 39 | src: 40 | "https://github.com/mjambon/biniou/releases/download/1.2.1/biniou-1.2.1.tbz" 41 | checksum: [ 42 | "sha256=35546c68b1929a8e6d27a3b39ecd17b38303a0d47e65eb9d1480c2061ea84335" 43 | "sha512=82670cc77bf3e869ee26e5fbe5a5affa45a22bc8b6c4bd7e85473912780e0111baca59b34a2c14feae3543ce6e239d7fddaeab24b686a65bfe642cdb91d27ebf" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /src/index.re: -------------------------------------------------------------------------------- 1 | [@bs.module] external _css: Js.t({..}) = "./index.scss"; 2 | 3 | [@bs.module "./serviceWorker"] 4 | external register_service_worker: unit => unit = "register"; 5 | [@bs.module "./serviceWorker"] 6 | external unregister_service_worker: unit => unit = "unregister"; 7 | 8 | module ReactDOM = { 9 | type root; 10 | 11 | [@bs.module "react-dom"] 12 | external createRoot: Dom.element => root = "unstable_createRoot"; 13 | 14 | [@bs.send] external render: (root, React.element) => unit = "render"; 15 | 16 | [@bs.val] [@bs.return nullable] 17 | external _getElementById: string => option(Dom.element) = 18 | "document.getElementById"; 19 | [@bs.val] 20 | external _getElementsByClassName: string => array(Dom.element) = 21 | "document.getElementsByClassName"; 22 | 23 | let renderToElementWithClassName = className => 24 | switch (_getElementsByClassName(className)) { 25 | | [||] => 26 | raise( 27 | Invalid_argument( 28 | "ReactDOMRe.Unstable.renderToElementWithClassName: no element of class " 29 | ++ className 30 | ++ " found in the HTML.", 31 | ), 32 | ) 33 | | elements => createRoot(Array.unsafe_get(elements, 0)) 34 | }; 35 | 36 | let createRootWithId = id => 37 | switch (_getElementById(id)) { 38 | | None => 39 | raise( 40 | Invalid_argument( 41 | "ReactDOMRe.Unstable.createRootWithId: no element of id " 42 | ++ id 43 | ++ " found in the HTML.", 44 | ), 45 | ) 46 | | Some(element) => createRoot(element) 47 | }; 48 | }; 49 | 50 | let start = () => { 51 | let root = ReactDOM.createRootWithId("root"); 52 | ReactDOM.render(root, ); 53 | }; 54 | 55 | start(); 56 | 57 | // If you want your app to work offline and load faster, you can change 58 | // unregister_service_worker() to register_service_worker() below. Note this 59 | // comes with some pitfalls. Learn more about service workers: 60 | // https://bit.ly/CRA-PWA 61 | unregister_service_worker(); 62 | -------------------------------------------------------------------------------- /esy.lock/opam/ocamlfind.1.8.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | synopsis: "A library manager for OCaml" 3 | maintainer: "Thomas Gazagnaire " 4 | authors: "Gerd Stolpmann " 5 | homepage: "http://projects.camlcity.org/projects/findlib.html" 6 | bug-reports: "https://gitlab.camlcity.org/gerd/lib-findlib/issues" 7 | dev-repo: "git+https://gitlab.camlcity.org/gerd/lib-findlib.git" 8 | description: """ 9 | Findlib is a library manager for OCaml. It provides a convention how 10 | to store libraries, and a file format ("META") to describe the 11 | properties of libraries. There is also a tool (ocamlfind) for 12 | interpreting the META files, so that it is very easy to use libraries 13 | in programs and scripts. 14 | """ 15 | build: [ 16 | [ 17 | "./configure" 18 | "-bindir" 19 | bin 20 | "-sitelib" 21 | lib 22 | "-mandir" 23 | man 24 | "-config" 25 | "%{lib}%/findlib.conf" 26 | "-no-custom" 27 | "-no-camlp4" {!ocaml:preinstalled & ocaml:version >= "4.02.0"} 28 | "-no-topfind" {ocaml:preinstalled} 29 | ] 30 | [make "all"] 31 | [make "opt"] {ocaml:native} 32 | ] 33 | install: [ 34 | [ 35 | "./configure" 36 | "-bindir" 37 | bin 38 | "-sitelib" 39 | lib 40 | "-mandir" 41 | man 42 | "-config" 43 | "%{lib}%/findlib.conf" 44 | "-no-custom" 45 | "-no-camlp4" {!ocaml:preinstalled & ocaml:version >= "4.02.0"} 46 | "-no-topfind" {ocaml:preinstalled} 47 | ] 48 | [make "install"] 49 | ["install" "-m" "0755" "ocaml-stub" "%{bin}%/ocaml"] {ocaml:preinstalled} 50 | ] 51 | depends: [ 52 | "ocaml" {>= "4.00.0" & < "4.13"} 53 | "conf-m4" {build} 54 | ] 55 | extra-files: [ 56 | ["ocamlfind.install" "md5=06f2c282ab52d93aa6adeeadd82a2543"] 57 | ["ocaml-stub" "md5=181f259c9e0bad9ef523e7d4abfdf87a"] 58 | ] 59 | url { 60 | src: "http://download.camlcity.org/download/findlib-1.8.1.tar.gz" 61 | checksum: "md5=18ca650982c15536616dea0e422cbd8c" 62 | mirrors: "http://download2.camlcity.org/download/findlib-1.8.1.tar.gz" 63 | } 64 | depopts: ["graphics"] 65 | -------------------------------------------------------------------------------- /esy.lock/opam/csexp.1.4.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | synopsis: "Parsing and printing of S-expressions in Canonical form" 3 | description: """ 4 | 5 | This library provides minimal support for Canonical S-expressions 6 | [1]. Canonical S-expressions are a binary encoding of S-expressions 7 | that is super simple and well suited for communication between 8 | programs. 9 | 10 | This library only provides a few helpers for simple applications. If 11 | you need more advanced support, such as parsing from more fancy input 12 | sources, you should consider copying the code of this library given 13 | how simple parsing S-expressions in canonical form is. 14 | 15 | To avoid a dependency on a particular S-expression library, the only 16 | module of this library is parameterised by the type of S-expressions. 17 | 18 | [1] https://en.wikipedia.org/wiki/Canonical_S-expressions 19 | """ 20 | maintainer: ["Jeremie Dimino "] 21 | authors: [ 22 | "Quentin Hocquet " 23 | "Jane Street Group, LLC " 24 | "Jeremie Dimino " 25 | ] 26 | license: "MIT" 27 | homepage: "https://github.com/ocaml-dune/csexp" 28 | doc: "https://ocaml-dune.github.io/csexp/" 29 | bug-reports: "https://github.com/ocaml-dune/csexp/issues" 30 | depends: [ 31 | "dune" {>= "1.11"} 32 | "ocaml" {>= "4.02.3"} 33 | "result" {>= "1.5"} 34 | ] 35 | dev-repo: "git+https://github.com/ocaml-dune/csexp.git" 36 | build: [ 37 | ["dune" "subst"] {pinned} 38 | [ 39 | "dune" 40 | "build" 41 | "-p" 42 | name 43 | "-j" 44 | jobs 45 | "@install" 46 | # "@runtest" {with-test & ocaml:version >= "4.04"} 47 | "@doc" {with-doc} 48 | ] 49 | ] 50 | x-commit-hash: "0e1b2044c8d1ff187c27cec3e46d9cde14892650" 51 | url { 52 | src: 53 | "https://github.com/ocaml-dune/csexp/releases/download/1.4.0/csexp-1.4.0.tbz" 54 | checksum: [ 55 | "sha256=8e3d6fca87f102a126dee8b72a2a0d146f10439c47218dfc149d51bf3edf364e" 56 | "sha512=604a5094fbbf61f497b342ad0aa8ec25275b2a904cd0c1823fc40daa54a15796b360374ff495c0d8ca3b4c1e6723b2ce37e030857fae131222606de818fb8129" 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "locked": { 5 | "lastModified": 1653893745, 6 | "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", 7 | "owner": "numtide", 8 | "repo": "flake-utils", 9 | "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "numtide", 14 | "repo": "flake-utils", 15 | "type": "github" 16 | } 17 | }, 18 | "flake-utils_2": { 19 | "locked": { 20 | "lastModified": 1653893745, 21 | "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", 22 | "owner": "numtide", 23 | "repo": "flake-utils", 24 | "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", 25 | "type": "github" 26 | }, 27 | "original": { 28 | "owner": "numtide", 29 | "repo": "flake-utils", 30 | "type": "github" 31 | } 32 | }, 33 | "nixpkgs": { 34 | "inputs": { 35 | "flake-utils": "flake-utils_2", 36 | "nixpkgs": "nixpkgs_2" 37 | }, 38 | "locked": { 39 | "lastModified": 1654213891, 40 | "narHash": "sha256-ErjCuja4IRQfmSU9O/guechrvBKSVRCh9buOqvC8VfU=", 41 | "owner": "anmonteiro", 42 | "repo": "nix-overlays", 43 | "rev": "db73276cffa767f07534d685dae6c836f87664e1", 44 | "type": "github" 45 | }, 46 | "original": { 47 | "owner": "anmonteiro", 48 | "repo": "nix-overlays", 49 | "type": "github" 50 | } 51 | }, 52 | "nixpkgs_2": { 53 | "locked": { 54 | "lastModified": 1654012153, 55 | "narHash": "sha256-In+gfoH2Tnf/UmpzeuGlfuexU2EC4QIelBsm2zMK5AE=", 56 | "owner": "NixOS", 57 | "repo": "nixpkgs", 58 | "rev": "49a2bcc6e2065909c701f862f9a1a62b3082b40a", 59 | "type": "github" 60 | }, 61 | "original": { 62 | "owner": "NixOS", 63 | "repo": "nixpkgs", 64 | "rev": "49a2bcc6e2065909c701f862f9a1a62b3082b40a", 65 | "type": "github" 66 | } 67 | }, 68 | "root": { 69 | "inputs": { 70 | "flake-utils": "flake-utils", 71 | "nixpkgs": "nixpkgs" 72 | } 73 | } 74 | }, 75 | "root": "root", 76 | "version": 7 77 | } 78 | -------------------------------------------------------------------------------- /src/utils.ml: -------------------------------------------------------------------------------- 1 | let dayOfWeek = function 2 | | 0 -> 3 | "Sunday" 4 | | 1 -> 5 | "Monday" 6 | | 2 -> 7 | "Tuesday" 8 | | 3 -> 9 | "Wednesday" 10 | | 4 -> 11 | "Thursday" 12 | | 5 -> 13 | "Friday" 14 | | 6 -> 15 | "Saturday" 16 | | _ -> 17 | assert false 18 | 19 | let formatDate d = 20 | dayOfWeek (Js.Date.getDay d |. int_of_float) 21 | ^ ", " 22 | ^ Js.Date.toLocaleString d 23 | 24 | module QueryParams = struct 25 | type t 26 | 27 | external make : string -> t = "URLSearchParams" [@@bs.new] 28 | 29 | external get : t -> string -> string option = "get" 30 | [@@bs.send] [@@bs.return nullable] 31 | end 32 | 33 | type window = 34 | < innerHeight : int ; pageXOffset : int ; pageYOffset : int > Js.t 35 | 36 | external window : window = "window" [@@bs.val] 37 | 38 | external documentElement : < scrollTop : int ; offsetHeight : int > Js.t = "documentElement" 39 | [@@bs.scope "document"] [@@bs.val] 40 | 41 | let throttle f ms = 42 | let last = ref max_float in 43 | let timer = ref None in 44 | fun arg -> 45 | let now = Js.Date.now () in 46 | if now < !last +. float ms then ( 47 | (match !timer with None -> () | Some id -> Js.Global.clearTimeout id); 48 | timer := 49 | Some 50 | (Js.Global.setTimeout 51 | (fun () -> 52 | last := Js.Date.now (); 53 | f arg) 54 | ms)) 55 | else ( 56 | last := Js.Date.now (); 57 | f arg) 58 | 59 | module Scroll = struct 60 | external onScroll 61 | : window 62 | -> (_[@bs.as "scroll"]) 63 | -> (Dom.event -> unit) 64 | -> unit 65 | = "addEventListener" 66 | [@@bs.send] 67 | 68 | external offScroll 69 | : window 70 | -> (_[@bs.as "scroll"]) 71 | -> (Dom.event -> unit) 72 | -> unit 73 | = "removeEventListener" 74 | [@@bs.send] 75 | 76 | type t = 77 | { x : int 78 | ; y : int 79 | } 80 | 81 | let useScroll () = 82 | let state, updateState = 83 | React.useState (fun () -> 84 | { x = window##pageXOffset; y = window##pageYOffset }) 85 | in 86 | let handler = 87 | throttle 88 | (fun _ -> 89 | updateState (fun _ -> 90 | { x = window##pageXOffset; y = window##pageYOffset })) 91 | 200 92 | in 93 | React.useEffect0 (fun () -> 94 | onScroll window handler; 95 | Some (fun () -> offScroll window handler)); 96 | state 97 | end 98 | -------------------------------------------------------------------------------- /esy.lock/opam/dune.2.8.4/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | synopsis: "Fast, portable, and opinionated build system" 3 | description: """ 4 | 5 | dune is a build system that was designed to simplify the release of 6 | Jane Street packages. It reads metadata from "dune" files following a 7 | very simple s-expression syntax. 8 | 9 | dune is fast, has very low-overhead, and supports parallel builds on 10 | all platforms. It has no system dependencies; all you need to build 11 | dune or packages using dune is OCaml. You don't need make or bash 12 | as long as the packages themselves don't use bash explicitly. 13 | 14 | dune supports multi-package development by simply dropping multiple 15 | repositories into the same directory. 16 | 17 | It also supports multi-context builds, such as building against 18 | several opam roots/switches simultaneously. This helps maintaining 19 | packages across several versions of OCaml and gives cross-compilation 20 | for free. 21 | """ 22 | maintainer: ["Jane Street Group, LLC "] 23 | authors: ["Jane Street Group, LLC "] 24 | license: "MIT" 25 | homepage: "https://github.com/ocaml/dune" 26 | doc: "https://dune.readthedocs.io/" 27 | bug-reports: "https://github.com/ocaml/dune/issues" 28 | conflicts: [ 29 | "merlin" {< "3.4.0"} 30 | "ocaml-lsp-server" {< "1.3.0"} 31 | "dune-configurator" {< "2.3.0"} 32 | "odoc" {< "1.3.0"} 33 | "dune-release" {< "1.3.0"} 34 | "js_of_ocaml-compiler" {< "3.6.0"} 35 | "jbuilder" {= "transition"} 36 | ] 37 | dev-repo: "git+https://github.com/ocaml/dune.git" 38 | build: [ 39 | # opam 2 sets OPAM_SWITCH_PREFIX, so we don't need a hardcoded path 40 | ["ocaml" "configure.ml" "--libdir" lib] {opam-version < "2"} 41 | ["ocaml" "bootstrap.ml" "-j" jobs] 42 | ["./dune.exe" "build" "-p" name "--profile" "dune-bootstrap" "-j" jobs] 43 | ] 44 | depends: [ 45 | # Please keep the lower bound in sync with .github/workflows/workflow.yml, 46 | # dune-project and min_ocaml_version in bootstrap.ml 47 | ("ocaml" {>= "4.08"} | ("ocaml" {< "4.08~~"} & "ocamlfind-secondary")) 48 | "base-unix" 49 | "base-threads" 50 | ] 51 | x-commit-hash: "b6a3f66fb15378fc7170e94778f4d2c0b142ad92" 52 | url { 53 | src: "https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz" 54 | checksum: [ 55 | "sha256=4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac" 56 | "sha512=efc1834c4add40138a101734665a1f462c19fe76d1cbb457b1fc20f95991118a50b24d485fb98d39046e41bec03885a8dc071bf8add51083ac9780bff9f6668a" 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /src/App.module.scss: -------------------------------------------------------------------------------- 1 | @import "./palette.scss"; 2 | @import "./units.scss"; 3 | 4 | /* App Header */ 5 | 6 | .appHeader { 7 | text-align: center; 8 | background-color: $blue; 9 | min-height: 15vmin; 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | justify-content: center; 14 | font-size: calc(10px + 2vmin); 15 | color: white; 16 | } 17 | 18 | .collapsible { 19 | margin-bottom: $m; 20 | transition: max-height 0.5s ease-in-out; 21 | overflow: hidden; 22 | max-height: 100px; 23 | } 24 | 25 | .collapsed { 26 | max-height: 0; 27 | } 28 | 29 | /* Main content */ 30 | 31 | .appMain { 32 | max-width: 1024px; 33 | margin: 30px auto; 34 | } 35 | 36 | .feedTitle { 37 | color: $baby; 38 | } 39 | 40 | /* Entries */ 41 | 42 | .entryDate { 43 | display: flex; 44 | font-weight: 500; 45 | margin-bottom: $s; 46 | } 47 | 48 | .entryContent { 49 | /* GitHub Theming */ 50 | :global { 51 | @import "@primer/css/core/index.scss"; 52 | @import "@primer/css/product/index.scss"; 53 | @import "~github-syntax-light/lib/github-light.css"; 54 | 55 | .repo-language-color { 56 | border-radius: 50%; 57 | display: inline-block; 58 | height: 12px; 59 | position: relative; 60 | top: 1px; 61 | width: 12px; 62 | } 63 | } 64 | } 65 | 66 | .loader, 67 | .loader:after { 68 | border-radius: 50%; 69 | width: 10em; 70 | height: 10em; 71 | } 72 | 73 | $cream_op: rgba(248, 255, 244, 0.2); 74 | 75 | .loader { 76 | margin: 60px auto; 77 | font-size: 10px; 78 | position: relative; 79 | text-indent: -9999em; 80 | border-top: 1.1em solid $cream_op; 81 | border-right: 1.1em solid $cream_op; 82 | border-bottom: 1.1em solid $cream_op; 83 | border-left: 1.1em solid $gray; 84 | -webkit-transform: translateZ(0); 85 | -ms-transform: translateZ(0); 86 | transform: translateZ(0); 87 | -webkit-animation: load8 1.1s infinite linear; 88 | animation: load8 1.1s infinite linear; 89 | } 90 | @-webkit-keyframes load8 { 91 | 0% { 92 | -webkit-transform: rotate(0deg); 93 | transform: rotate(0deg); 94 | } 95 | 100% { 96 | -webkit-transform: rotate(360deg); 97 | transform: rotate(360deg); 98 | } 99 | } 100 | @keyframes load8 { 101 | 0% { 102 | -webkit-transform: rotate(0deg); 103 | transform: rotate(0deg); 104 | } 105 | 100% { 106 | -webkit-transform: rotate(360deg); 107 | transform: rotate(360deg); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /esy.lock/opam/merlin.4.1-412/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "defree@gmail.com" 3 | authors: "The Merlin team" 4 | homepage: "https://github.com/ocaml/merlin" 5 | bug-reports: "https://github.com/ocaml/merlin/issues" 6 | dev-repo: "git+https://github.com/ocaml/merlin.git" 7 | build: [ 8 | ["dune" "subst"] {pinned} 9 | ["dune" "build" "-p" name "-j" jobs] 10 | ["dune" "runtest" "-p" "merlin,dot-merlin-reader" "-j" "1"] {with-test} 11 | ] 12 | depends: [ 13 | "ocaml" {>= "4.12" & < "4.13"} 14 | "dune" {>= "2.7.0"} 15 | "dot-merlin-reader" {>= "4.0"} 16 | "yojson" {>= "1.6.0"} 17 | "conf-jq" {with-test} 18 | "csexp" {>= "1.2.3"} 19 | "result" {>= "1.5"} 20 | "menhir" {dev} 21 | "menhirLib" {dev} 22 | "menhirSdk" {dev} 23 | ] 24 | synopsis: 25 | "Editor helper, provides completion, typing and source browsing in Vim and Emacs" 26 | description: 27 | "Merlin is an assistant for editing OCaml code. It aims to provide the features available in modern IDEs: error reporting, auto completion, source browsing and much more." 28 | post-messages: [ 29 | "merlin installed. 30 | 31 | Quick setup for VIM 32 | ------------------- 33 | Append this to your .vimrc to add merlin to vim's runtime-path: 34 | let g:opamshare = substitute(system('opam var share'),'\\n$','','''') 35 | execute \"set rtp+=\" . g:opamshare . \"/merlin/vim\" 36 | 37 | Also run the following line in vim to index the documentation: 38 | :execute \"helptags \" . g:opamshare . \"/merlin/vim/doc\" 39 | 40 | Quick setup for EMACS 41 | ------------------- 42 | Add opam emacs directory to your load-path by appending this to your .emacs: 43 | (let ((opam-share (ignore-errors (car (process-lines \"opam\" \"config\" \"var\" \"share\"))))) 44 | (when (and opam-share (file-directory-p opam-share)) 45 | ;; Register Merlin 46 | (add-to-list 'load-path (expand-file-name \"emacs/site-lisp\" opam-share)) 47 | (autoload 'merlin-mode \"merlin\" nil t nil) 48 | ;; Automatically start it in OCaml buffers 49 | (add-hook 'tuareg-mode-hook 'merlin-mode t) 50 | (add-hook 'caml-mode-hook 'merlin-mode t) 51 | ;; Use opam switch to lookup ocamlmerlin binary 52 | (setq merlin-command 'opam))) 53 | 54 | Take a look at https://github.com/ocaml/merlin for more information 55 | 56 | Quick setup with opam-user-setup 57 | -------------------------------- 58 | 59 | Opam-user-setup support Merlin. 60 | 61 | $ opam user-setup install 62 | 63 | should take care of basic setup. 64 | See https://github.com/OCamlPro/opam-user-setup 65 | " 66 | {success & !user-setup:installed} 67 | ] 68 | x-commit-hash: "35c3ad0fb4a1de53f6afb028961800e63b9363bd" 69 | url { 70 | src: 71 | "https://github.com/ocaml/merlin/releases/download/v4.1-412/merlin-v4.1-412.tbz" 72 | checksum: [ 73 | "sha256=fb4caede73bdb8393bd60e31792af74b901ae2d319ac2f2a2252c694d2069d8d" 74 | "sha512=ec301e0f97e11c1c331478030372d373d381a0ddbb7f72c83f7baa4c2c6d4f26094c3398f56bcf3d40c1242044391369fd06e8cd2ccfe1f5d78467eb3e9d33be" 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /src/App.re: -------------------------------------------------------------------------------- 1 | open Belt; 2 | 3 | [@bs.module] external css: Js.t({..}) as 'a = "./App.module.scss"; 4 | 5 | module Entry = { 6 | module Entry = Feed.Entry; 7 | 8 | [@react.component] 9 | let make = (~entry) => { 10 | let date = { 11 | let dateMs = 12 | switch (entry.Entry.published) { 13 | | Some(published) => published 14 | | None => entry.updated 15 | }; 16 | let jsDate = Js.Date.fromFloat(dateMs); 17 | Utils.formatDate(jsDate); 18 | }; 19 | let dateCaption = "On " ++ date ++ ":"; 20 |
21 | 22 |
23 | {switch (entry.links) { 24 | | [] => React.string(dateCaption) 25 | | [{Feed.Link.title, href}, ..._] => 26 | {React.string(dateCaption)} 27 | }} 28 |
29 | {switch (entry.content) { 30 | | Some(content) => 31 |
35 | | None => React.null 36 | }} 37 | 38 |
; 39 | }; 40 | }; 41 | 42 | module Header = { 43 | let feedTitle = (~link=?, feedTitle) => { 44 | switch (link) { 45 | | Some({Feed.Link.title, href}) => 46 | {React.string(feedTitle)} 47 | | None => 48 | {React.string(feedTitle)} 49 | }; 50 | }; 51 | 52 | [@react.component] 53 | let make = (~link=?, ~title) => { 54 |
55 |

{feedTitle(~link?, title)}

56 |
; 57 | }; 58 | }; 59 | 60 | module FeedPage = { 61 | [@react.component] 62 | let make = (~token=?, ~page, ~user, ~loadingRef) => { 63 | let {Api.SWR.data, error: _error} = 64 | Api.SWR.useSWR(Api.feedEndpoint(~token?, ~page, user)); 65 | 66 | /* If this is executed, it means the data was successfully read from the 67 | * remote endpoint. We are done loading. */ 68 | React.useEffect0(() => { 69 | loadingRef.React.current = false; 70 | None; 71 | }); 72 | 73 |
74 | {switch (data) { 75 | | Some(Ok({Feed.entries})) => 76 | entries 77 | ->List.reduceWithIndexU( 78 | Array.makeUninitializedUnsafe(List.length(entries)), 79 | (. arr, entry, i) => { 80 | Array.setUnsafe( 81 | arr, 82 | i, 83 | , 84 | ); 85 | arr; 86 | }, 87 | ) 88 | ->React.array 89 | | Some(Error(_)) 90 | | None => React.null 91 | }} 92 |
; 93 | }; 94 | }; 95 | 96 | module GithubFeed = { 97 | [@react.component] 98 | let make = (~token=?, ~user, ~page, ~loadingRef) => { 99 | /* first page is always shown, and we need it to show the header */ 100 | let {Api.SWR.data, error: _error} = 101 | Api.SWR.useSWR(Api.feedEndpoint(~token?, ~page=1, user)); 102 | let (link, title) = 103 | switch (data) { 104 | | Some(Ok({Feed.links, title})) => 105 | switch (links) { 106 | | [link, ..._] => (Some(link), title) 107 | | _ => (None, title) 108 | } 109 | | Some(Error(msg)) => (None, Format.asprintf("Error: %s", msg)) 110 | | None => (None, "ERROR TODO" /* Format.asprintf("Error: %s", msg) */) 111 | }; 112 | 113 | <> 114 |
115 |
116 | {React.array( 117 | Array.makeByU(page, (. i) => 118 | }> 119 | 120 | 121 | ), 122 | )} 123 |
124 | ; 125 | }; 126 | }; 127 | 128 | /* TODO: insert a username to fetch */ 129 | [@react.component] 130 | let make = () => { 131 | open Utils; 132 | let {RescriptReactRouter.search, path} = RescriptReactRouter.useUrl(); 133 | let (page, setPage) = React.useState(() => 1); 134 | let {Scroll.y, _} = Scroll.useScroll(); 135 | let loadingRef = React.useRef(false); 136 | 137 | React.useEffect3( 138 | () => { 139 | let loading = loadingRef.current; 140 | if (!loading) { 141 | let totalHeight = window##innerHeight + y; 142 | let offsetHeight = documentElement##offsetHeight; 143 | /* allow a 20px epsilon */ 144 | if (totalHeight === offsetHeight) { 145 | loadingRef.current = true; 146 | setPage(prev => prev + 1); 147 | }; 148 | }; 149 | None; 150 | }, 151 | (page, setPage, y), 152 | ); 153 | 154 | let qp = QueryParams.make(search); 155 | let (user, token) = { 156 | let user = 157 | switch (path) { 158 | | [user, ..._] => user 159 | | _ => "anmonteiro" 160 | }; 161 | (user, QueryParams.get(qp, "token")); 162 | }; 163 | 164 | 165 |
166 | }> 167 | 168 | 169 |
170 |
; 171 | }; 172 | -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /lambda/lambda.ml: -------------------------------------------------------------------------------- 1 | open Util 2 | open Syndic 3 | open Lwt.Infix 4 | 5 | let send_response body = 6 | let open Vercel in 7 | let body = Yojson.Safe.to_string body in 8 | let response = 9 | Response.of_string 10 | ~headers:(Headers.of_list [ "content-type", "application/json" ]) 11 | ~body 12 | `OK 13 | in 14 | Ok response 15 | 16 | let send_error_response msg = 17 | let open Vercel in 18 | let payload = `Assoc [ "error", `String msg ] in 19 | let body = Yojson.Safe.to_string payload in 20 | let response = 21 | Response.of_string 22 | ~headers:(Headers.of_list [ "content-type", "application/json" ]) 23 | ~body 24 | `Bad_request 25 | in 26 | Ok response 27 | 28 | let replace_hrefs xml_base html_string = 29 | let tree = Soup.parse html_string in 30 | let anchors = Soup.select "a" tree in 31 | Soup.iter 32 | (fun a -> 33 | match Soup.attribute "href" a with 34 | | None -> 35 | () 36 | | Some href -> 37 | let uri = Uri.resolve "" xml_base (Uri.of_string href) in 38 | Soup.set_attribute "href" (Uri.to_string uri) a) 39 | anchors; 40 | Soup.to_string tree 41 | 42 | let text_construct_to_string : Atom.text_construct -> string = function 43 | | Atom.Text s -> 44 | s 45 | | Html (_, s) -> 46 | s 47 | | Xhtml (_, _) -> 48 | assert false 49 | 50 | let content_to_string : Atom.content -> string = function 51 | | Atom.Text s -> 52 | s 53 | | Atom.Html (uri, s) -> 54 | (match uri with Some uri -> replace_hrefs uri s | None -> s) 55 | | Atom.Src (_, _) | Atom.Xhtml (_, _) -> 56 | assert false 57 | | Atom.Mime (_, s) -> 58 | s 59 | 60 | let ptime_to_timestamp t = 61 | (* Ptime counts seconds, we return milliseconds *) 62 | Ptime.to_float_s t *. 1000. 63 | 64 | let build_link { Atom.href; title; _ } = 65 | { Feed.Link.href = Uri.to_string href; title } 66 | 67 | let build_author { Atom.name; uri; email } = 68 | { Feed.Author.name; email; uri = Option.map ~f:Uri.to_string uri } 69 | 70 | let build_entry 71 | { Atom.authors = main_author, other_authors 72 | ; content 73 | ; id 74 | ; links 75 | ; published 76 | ; title 77 | ; updated 78 | ; _ 79 | } 80 | = 81 | { Feed.Entry.authors = 82 | build_author main_author, List.map build_author other_authors 83 | ; content = Option.map ~f:content_to_string content 84 | ; id = Uri.to_string id 85 | ; links = List.map build_link links 86 | ; published = Option.map ~f:ptime_to_timestamp published 87 | ; title = text_construct_to_string title 88 | ; updated = ptime_to_timestamp updated 89 | } 90 | 91 | let handle source = 92 | let input = Xmlm.make_input source in 93 | let { Atom.authors; id; links; logo; subtitle; title; updated; entries; _ } = 94 | Atom.parse ~xmlbase:(Uri.of_string "https://github.com") input 95 | in 96 | { Feed.authors = List.map build_author authors 97 | ; id = Uri.to_string id 98 | ; links = List.map build_link links 99 | ; logo = Option.map ~f:Uri.to_string logo 100 | ; subtitle = Option.map ~f:text_construct_to_string subtitle 101 | ; title = text_construct_to_string title 102 | ; updated = ptime_to_timestamp updated 103 | ; entries = List.map build_entry entries 104 | } 105 | 106 | let get_feed ?page ?token user = 107 | let base_url = Format.asprintf "https://github.com/%s" user in 108 | let feed_url, has_query_param = 109 | match token with 110 | | Some token -> 111 | Format.asprintf "%s.private.atom?token=%s" base_url token, true 112 | | None -> 113 | Format.asprintf "%s.atom" base_url, false 114 | in 115 | let uri = 116 | match page with 117 | | Some page -> 118 | Format.asprintf 119 | "%s%cpage=%s" 120 | feed_url 121 | (if has_query_param then '&' else '?') 122 | page 123 | | None -> 124 | feed_url 125 | in 126 | Piaf.Client.Oneshot.get 127 | ~config: 128 | { Piaf.Config.default with 129 | follow_redirects = true 130 | ; cacert = Some (Piaf.Cert.Filepath "./cacert.pem") 131 | } 132 | ~headers:[ "accept", "text/html,application/xhtml+xml,application/xml" ] 133 | (Uri.of_string uri) 134 | >>= function 135 | | Ok { Piaf.Response.body; _ } -> 136 | Piaf.Body.to_string body 137 | | Error msg -> 138 | Lwt_result.fail msg 139 | 140 | let handler reqd _ctx = 141 | let { Piaf.Request.target; _ } = reqd in 142 | let usage = "Usage:\n gh-feed.anmonteiro.now.sh/?user=username&page=N" in 143 | let uri = Uri.of_string target in 144 | let page = Uri.get_query_param uri "page" in 145 | let token = Uri.get_query_param uri "token" in 146 | match Uri.get_query_param uri "user" with 147 | | Some user -> 148 | get_feed ?page ?token user >>= ( function 149 | | Ok feed -> 150 | let feed_json = handle (`String (0, feed)) |> Feed.to_yojson in 151 | Lwt.return (send_response feed_json) 152 | | Error e -> 153 | let msg = Piaf.Error.to_string e in 154 | Lwt.return (send_error_response msg) ) 155 | | None -> 156 | Lwt.return (send_error_response usage) 157 | 158 | let setup_log ?style_renderer level = 159 | Fmt_tty.setup_std_outputs ?style_renderer (); 160 | Logs.set_level (Some level); 161 | Logs.set_reporter (Logs_fmt.reporter ()) 162 | 163 | let () = 164 | setup_log Logs.Debug; 165 | let () = 166 | try 167 | Logs.debug (fun m -> m "Trying to set KQueue backend for libev"); 168 | Lwt_engine.(set (new libev ~backend:Ev_backend.kqueue ())) 169 | with 170 | | _ -> 171 | Logs.debug (fun m -> 172 | m "Failed setting KQueue libev backend. Falling back to epoll.\n%!"); 173 | Lwt_engine.(set (new libev ~backend:Ev_backend.epoll ())) 174 | in 175 | Vercel.io_lambda handler 176 | -------------------------------------------------------------------------------- /esy.lock/overrides/opam__s__ocamlfind_opam__c__1.8.1_opam_override/files/findlib-1.8.1.patch: -------------------------------------------------------------------------------- 1 | --- ./Makefile 2 | +++ ./Makefile 3 | @@ -57,16 +57,16 @@ 4 | cat findlib.conf.in | \ 5 | $(SH) tools/patch '@SITELIB@' '$(OCAML_SITELIB)' >findlib.conf 6 | if ./tools/cmd_from_same_dir ocamlc; then \ 7 | - echo 'ocamlc="ocamlc.opt"' >>findlib.conf; \ 8 | + echo 'ocamlc="ocamlc.opt$(EXEC_SUFFIX)"' >>findlib.conf; \ 9 | fi 10 | if ./tools/cmd_from_same_dir ocamlopt; then \ 11 | - echo 'ocamlopt="ocamlopt.opt"' >>findlib.conf; \ 12 | + echo 'ocamlopt="ocamlopt.opt$(EXEC_SUFFIX)"' >>findlib.conf; \ 13 | fi 14 | if ./tools/cmd_from_same_dir ocamldep; then \ 15 | - echo 'ocamldep="ocamldep.opt"' >>findlib.conf; \ 16 | + echo 'ocamldep="ocamldep.opt$(EXEC_SUFFIX)"' >>findlib.conf; \ 17 | fi 18 | if ./tools/cmd_from_same_dir ocamldoc; then \ 19 | - echo 'ocamldoc="ocamldoc.opt"' >>findlib.conf; \ 20 | + echo 'ocamldoc="ocamldoc.opt$(EXEC_SUFFIX)"' >>findlib.conf; \ 21 | fi 22 | 23 | .PHONY: install-doc 24 | --- ./src/findlib/findlib_config.mlp 25 | +++ ./src/findlib/findlib_config.mlp 26 | @@ -24,3 +24,5 @@ 27 | | "MacOS" -> "" (* don't know *) 28 | | _ -> failwith "Unknown Sys.os_type" 29 | ;; 30 | + 31 | +let exec_suffix = "@EXEC_SUFFIX@";; 32 | --- ./src/findlib/findlib.ml 33 | +++ ./src/findlib/findlib.ml 34 | @@ -28,15 +28,20 @@ 35 | let conf_ldconf = ref "";; 36 | let conf_ignore_dups_in = ref ([] : string list);; 37 | 38 | -let ocamlc_default = "ocamlc";; 39 | -let ocamlopt_default = "ocamlopt";; 40 | -let ocamlcp_default = "ocamlcp";; 41 | -let ocamloptp_default = "ocamloptp";; 42 | -let ocamlmklib_default = "ocamlmklib";; 43 | -let ocamlmktop_default = "ocamlmktop";; 44 | -let ocamldep_default = "ocamldep";; 45 | -let ocamlbrowser_default = "ocamlbrowser";; 46 | -let ocamldoc_default = "ocamldoc";; 47 | +let add_exec str = 48 | + match Findlib_config.exec_suffix with 49 | + | "" -> str 50 | + | a -> str ^ a ;; 51 | +let ocamlc_default = add_exec "ocamlc";; 52 | +let ocamlopt_default = add_exec "ocamlopt";; 53 | +let ocamlcp_default = add_exec "ocamlcp";; 54 | +let ocamloptp_default = add_exec "ocamloptp";; 55 | +let ocamlmklib_default = add_exec "ocamlmklib";; 56 | +let ocamlmktop_default = add_exec "ocamlmktop";; 57 | +let ocamldep_default = add_exec "ocamldep";; 58 | +let ocamlbrowser_default = add_exec "ocamlbrowser";; 59 | +let ocamldoc_default = add_exec "ocamldoc";; 60 | + 61 | 62 | 63 | let init_manually 64 | --- ./src/findlib/fl_package_base.ml 65 | +++ ./src/findlib/fl_package_base.ml 66 | @@ -133,7 +133,15 @@ 67 | List.find (fun def -> def.def_var = "exists_if") p.package_defs in 68 | let files = Fl_split.in_words def.def_value in 69 | List.exists 70 | - (fun file -> Sys.file_exists (Filename.concat d' file)) 71 | + (fun file -> 72 | + let fln = Filename.concat d' file in 73 | + let e = Sys.file_exists fln in 74 | + (* necessary for ppx executables *) 75 | + if e || Sys.os_type <> "Win32" || Filename.check_suffix fln ".exe" then 76 | + e 77 | + else 78 | + Sys.file_exists (fln ^ ".exe") 79 | + ) 80 | files 81 | with Not_found -> true in 82 | 83 | --- ./src/findlib/fl_split.ml 84 | +++ ./src/findlib/fl_split.ml 85 | @@ -126,10 +126,17 @@ 86 | | '/' | '\\' -> true 87 | | _ -> false in 88 | let norm_dir_win() = 89 | - if l >= 1 && s.[0] = '/' then 90 | - Buffer.add_char b '\\' else Buffer.add_char b s.[0]; 91 | - if l >= 2 && s.[1] = '/' then 92 | - Buffer.add_char b '\\' else Buffer.add_char b s.[1]; 93 | + if l >= 1 then ( 94 | + if s.[0] = '/' then 95 | + Buffer.add_char b '\\' 96 | + else 97 | + Buffer.add_char b s.[0] ; 98 | + if l >= 2 then 99 | + if s.[1] = '/' then 100 | + Buffer.add_char b '\\' 101 | + else 102 | + Buffer.add_char b s.[1]; 103 | + ); 104 | for k = 2 to l - 1 do 105 | let c = s.[k] in 106 | if is_slash c then ( 107 | --- ./src/findlib/frontend.ml 108 | +++ ./src/findlib/frontend.ml 109 | @@ -31,10 +31,18 @@ 110 | else 111 | Sys_error (arg ^ ": " ^ Unix.error_message code) 112 | 113 | +let is_win = Sys.os_type = "Win32" 114 | + 115 | +let () = 116 | + match Findlib_config.system with 117 | + | "win32" | "win64" | "mingw" | "cygwin" | "mingw64" | "cygwin64" -> 118 | + (try set_binary_mode_out stdout true with _ -> ()); 119 | + (try set_binary_mode_out stderr true with _ -> ()); 120 | + | _ -> () 121 | 122 | let slashify s = 123 | match Findlib_config.system with 124 | - | "mingw" | "mingw64" | "cygwin" -> 125 | + | "win32" | "win64" | "mingw" | "cygwin" | "mingw64" | "cygwin64" -> 126 | let b = Buffer.create 80 in 127 | String.iter 128 | (function 129 | @@ -49,7 +57,7 @@ 130 | 131 | let out_path ?(prefix="") s = 132 | match Findlib_config.system with 133 | - | "mingw" | "mingw64" | "cygwin" -> 134 | + | "win32" | "win64" | "mingw" | "mingw64" | "cygwin" -> 135 | let u = slashify s in 136 | prefix ^ 137 | (if String.contains u ' ' then 138 | @@ -273,11 +281,9 @@ 139 | 140 | 141 | let identify_dir d = 142 | - match Sys.os_type with 143 | - | "Win32" -> 144 | - failwith "identify_dir" (* not available *) 145 | - | _ -> 146 | - let s = Unix.stat d in 147 | + if is_win then 148 | + failwith "identify_dir"; (* not available *) 149 | + let s = Unix.stat d in 150 | (s.Unix.st_dev, s.Unix.st_ino) 151 | ;; 152 | 153 | @@ -459,6 +465,96 @@ 154 | ) 155 | packages 156 | 157 | +let rewrite_cmd s = 158 | + if s = "" || not is_win then 159 | + s 160 | + else 161 | + let s = 162 | + let l = String.length s in 163 | + let b = Buffer.create l in 164 | + for i = 0 to pred l do 165 | + match s.[i] with 166 | + | '/' -> Buffer.add_char b '\\' 167 | + | x -> Buffer.add_char b x 168 | + done; 169 | + Buffer.contents b 170 | + in 171 | + if (Filename.is_implicit s && String.contains s '\\' = false) || 172 | + Filename.check_suffix (String.lowercase s) ".exe" then 173 | + s 174 | + else 175 | + let s' = s ^ ".exe" in 176 | + if Sys.file_exists s' then 177 | + s' 178 | + else 179 | + s 180 | + 181 | +let rewrite_cmd s = 182 | + if s = "" || not is_win then s else 183 | + let s = 184 | + let l = String.length s in 185 | + let b = Buffer.create l in 186 | + for i = 0 to pred l do 187 | + match s.[i] with 188 | + | '/' -> Buffer.add_char b '\\' 189 | + | x -> Buffer.add_char b x 190 | + done; 191 | + Buffer.contents b 192 | + in 193 | + if (Filename.is_implicit s && String.contains s '\\' = false) || 194 | + Filename.check_suffix (String.lowercase s) ".exe" then 195 | + s 196 | + else 197 | + let s' = s ^ ".exe" in 198 | + if Sys.file_exists s' then 199 | + s' 200 | + else 201 | + s 202 | + 203 | +let rewrite_pp cmd = 204 | + if not is_win then cmd else 205 | + let module T = struct exception Keep end in 206 | + let is_whitespace = function 207 | + | ' ' | '\011' | '\012' | '\n' | '\r' | '\t' -> true 208 | + | _ -> false in 209 | + (* characters that triggers special behaviour (cmd.exe, not unix shell) *) 210 | + let is_unsafe_char = function 211 | + | '(' | ')' | '%' | '!' | '^' | '<' | '>' | '&' -> true 212 | + | _ -> false in 213 | + let len = String.length cmd in 214 | + let buf = Buffer.create (len + 4) in 215 | + let buf_cmd = Buffer.create len in 216 | + let rec iter_ws i = 217 | + if i >= len then () else 218 | + let cur = cmd.[i] in 219 | + if is_whitespace cur then ( 220 | + Buffer.add_char buf cur; 221 | + iter_ws (succ i) 222 | + ) 223 | + else 224 | + iter_cmd i 225 | + and iter_cmd i = 226 | + if i >= len then add_buf_cmd () else 227 | + let cur = cmd.[i] in 228 | + if is_unsafe_char cur || cur = '"' || cur = '\'' then 229 | + raise T.Keep; 230 | + if is_whitespace cur then ( 231 | + add_buf_cmd (); 232 | + Buffer.add_substring buf cmd i (len - i) 233 | + ) 234 | + else ( 235 | + Buffer.add_char buf_cmd cur; 236 | + iter_cmd (succ i) 237 | + ) 238 | + and add_buf_cmd () = 239 | + if Buffer.length buf_cmd > 0 then 240 | + Buffer.add_string buf (rewrite_cmd (Buffer.contents buf_cmd)) 241 | + in 242 | + try 243 | + iter_ws 0; 244 | + Buffer.contents buf 245 | + with 246 | + | T.Keep -> cmd 247 | 248 | let process_pp_spec syntax_preds packages pp_opts = 249 | (* Returns: pp_command *) 250 | @@ -549,7 +645,7 @@ 251 | None -> [] 252 | | Some cmd -> 253 | ["-pp"; 254 | - cmd ^ " " ^ 255 | + (rewrite_cmd cmd) ^ " " ^ 256 | String.concat " " (List.map Filename.quote pp_i_options) ^ " " ^ 257 | String.concat " " (List.map Filename.quote pp_archives) ^ " " ^ 258 | String.concat " " (List.map Filename.quote pp_opts)] 259 | @@ -625,9 +721,11 @@ 260 | in 261 | try 262 | let preprocessor = 263 | + rewrite_cmd ( 264 | resolve_path 265 | ~base ~explicit:true 266 | - (package_property predicates pname "ppx") in 267 | + (package_property predicates pname "ppx") ) 268 | + in 269 | ["-ppx"; String.concat " " (preprocessor :: options)] 270 | with Not_found -> [] 271 | ) 272 | @@ -895,6 +993,14 @@ 273 | switch (e.g. -L instead of -L ) 274 | *) 275 | 276 | +(* We may need to remove files on which we do not have complete control. 277 | + On Windows, removing a read-only file fails so try to change the 278 | + mode of the file first. *) 279 | +let remove_file fname = 280 | + try Sys.remove fname 281 | + with Sys_error _ when is_win -> 282 | + (try Unix.chmod fname 0o666 with Unix.Unix_error _ -> ()); 283 | + Sys.remove fname 284 | 285 | let ocamlc which () = 286 | 287 | @@ -1022,9 +1128,12 @@ 288 | 289 | "-intf", 290 | Arg.String (fun s -> pass_files := !pass_files @ [ Intf(slashify s) ]); 291 | - 292 | + 293 | "-pp", 294 | - Arg.String (fun s -> pp_specified := true; add_spec_fn "-pp" s); 295 | + Arg.String (fun s -> pp_specified := true; add_spec_fn "-pp" (rewrite_pp s)); 296 | + 297 | + "-ppx", 298 | + Arg.String (fun s -> add_spec_fn "-ppx" (rewrite_pp s)); 299 | 300 | "-thread", 301 | Arg.Unit (fun _ -> threads := threads_default); 302 | @@ -1237,7 +1346,7 @@ 303 | with 304 | any -> 305 | close_out initl; 306 | - Sys.remove initl_file_name; 307 | + remove_file initl_file_name; 308 | raise any 309 | end; 310 | 311 | @@ -1245,9 +1354,9 @@ 312 | at_exit 313 | (fun () -> 314 | let tr f x = try f x with _ -> () in 315 | - tr Sys.remove initl_file_name; 316 | - tr Sys.remove (Filename.chop_extension initl_file_name ^ ".cmi"); 317 | - tr Sys.remove (Filename.chop_extension initl_file_name ^ ".cmo"); 318 | + tr remove_file initl_file_name; 319 | + tr remove_file (Filename.chop_extension initl_file_name ^ ".cmi"); 320 | + tr remove_file (Filename.chop_extension initl_file_name ^ ".cmo"); 321 | ); 322 | 323 | let exclude_list = [ stdlibdir; threads_dir; vmthreads_dir ] in 324 | @@ -1493,7 +1602,9 @@ 325 | [ "-v", Arg.Unit (fun () -> verbose := Verbose); 326 | "-pp", Arg.String (fun s -> 327 | pp_specified := true; 328 | - options := !options @ ["-pp"; s]); 329 | + options := !options @ ["-pp"; rewrite_pp s]); 330 | + "-ppx", Arg.String (fun s -> 331 | + options := !options @ ["-ppx"; rewrite_pp s]); 332 | ] 333 | ) 334 | ) 335 | @@ -1672,7 +1783,9 @@ 336 | Arg.String (fun s -> add_spec_fn "-I" (slashify (resolve_path s))); 337 | 338 | "-pp", Arg.String (fun s -> pp_specified := true; 339 | - add_spec_fn "-pp" s); 340 | + add_spec_fn "-pp" (rewrite_pp s)); 341 | + "-ppx", Arg.String (fun s -> add_spec_fn "-ppx" (rewrite_pp s)); 342 | + 343 | ] 344 | ) 345 | ) 346 | @@ -1830,7 +1943,10 @@ 347 | output_string ch_out append; 348 | close_out ch_out; 349 | close_in ch_in; 350 | - Unix.utimes outpath s.Unix.st_mtime s.Unix.st_mtime; 351 | + (try Unix.utimes outpath s.Unix.st_mtime s.Unix.st_mtime 352 | + with Unix.Unix_error(e,_,_) -> 353 | + prerr_endline("Warning: setting utimes for " ^ outpath 354 | + ^ ": " ^ Unix.error_message e)); 355 | 356 | prerr_endline("Installed " ^ outpath); 357 | with 358 | @@ -1882,6 +1998,8 @@ 359 | Unix.openfile (Filename.concat dir owner_file) [Unix.O_RDONLY] 0 in 360 | let f = 361 | Unix.in_channel_of_descr fd in 362 | + if is_win then 363 | + set_binary_mode_in f false; 364 | try 365 | let line = input_line f in 366 | let is_my_file = (line = pkg) in 367 | @@ -2208,7 +2326,7 @@ 368 | let lines = read_ldconf !ldconf in 369 | let dlldir_norm = Fl_split.norm_dir dlldir in 370 | let dlldir_norm_lc = string_lowercase_ascii dlldir_norm in 371 | - let ci_filesys = (Sys.os_type = "Win32") in 372 | + let ci_filesys = is_win in 373 | let check_dir d = 374 | let d' = Fl_split.norm_dir d in 375 | (d' = dlldir_norm) || 376 | @@ -2356,7 +2474,7 @@ 377 | List.iter 378 | (fun file -> 379 | let absfile = Filename.concat dlldir file in 380 | - Sys.remove absfile; 381 | + remove_file absfile; 382 | prerr_endline ("Removed " ^ absfile) 383 | ) 384 | dll_files 385 | @@ -2365,7 +2483,7 @@ 386 | (* Remove the files from the package directory: *) 387 | if Sys.file_exists pkgdir then begin 388 | let files = Sys.readdir pkgdir in 389 | - Array.iter (fun f -> Sys.remove (Filename.concat pkgdir f)) files; 390 | + Array.iter (fun f -> remove_file (Filename.concat pkgdir f)) files; 391 | Unix.rmdir pkgdir; 392 | prerr_endline ("Removed " ^ pkgdir) 393 | end 394 | @@ -2415,7 +2533,9 @@ 395 | 396 | 397 | let print_configuration() = 398 | + let sl = slashify in 399 | let dir s = 400 | + let s = sl s in 401 | if Sys.file_exists s then 402 | s 403 | else 404 | @@ -2453,27 +2573,27 @@ 405 | if md = "" then "the corresponding package directories" else dir md 406 | ); 407 | Printf.printf "The standard library is assumed to reside in:\n %s\n" 408 | - (Findlib.ocaml_stdlib()); 409 | + (sl (Findlib.ocaml_stdlib())); 410 | Printf.printf "The ld.conf file can be found here:\n %s\n" 411 | - (Findlib.ocaml_ldconf()); 412 | + (sl (Findlib.ocaml_ldconf())); 413 | flush stdout 414 | | Some "conf" -> 415 | - print_endline (Findlib.config_file()) 416 | + print_endline (sl (Findlib.config_file())) 417 | | Some "path" -> 418 | - List.iter print_endline (Findlib.search_path()) 419 | + List.iter ( fun x -> print_endline (sl x)) (Findlib.search_path()) 420 | | Some "destdir" -> 421 | - print_endline (Findlib.default_location()) 422 | + print_endline ( sl (Findlib.default_location())) 423 | | Some "metadir" -> 424 | - print_endline (Findlib.meta_directory()) 425 | + print_endline ( sl (Findlib.meta_directory())) 426 | | Some "metapath" -> 427 | let mdir = Findlib.meta_directory() in 428 | let ddir = Findlib.default_location() in 429 | - print_endline 430 | - (if mdir <> "" then mdir ^ "/META.%s" else ddir ^ "/%s/META") 431 | + print_endline ( sl 432 | + (if mdir <> "" then mdir ^ "/META.%s" else ddir ^ "/%s/META")) 433 | | Some "stdlib" -> 434 | - print_endline (Findlib.ocaml_stdlib()) 435 | + print_endline ( sl (Findlib.ocaml_stdlib())) 436 | | Some "ldconf" -> 437 | - print_endline (Findlib.ocaml_ldconf()) 438 | + print_endline ( sl (Findlib.ocaml_ldconf())) 439 | | _ -> 440 | assert false 441 | ;; 442 | @@ -2481,7 +2601,7 @@ 443 | 444 | let ocamlcall pkg cmd = 445 | let dir = package_directory pkg in 446 | - let path = Filename.concat dir cmd in 447 | + let path = rewrite_cmd (Filename.concat dir cmd) in 448 | begin 449 | try Unix.access path [ Unix.X_OK ] 450 | with 451 | @@ -2647,6 +2767,10 @@ 452 | | Sys_error f -> 453 | prerr_endline ("ocamlfind: " ^ f); 454 | exit 2 455 | + | Unix.Unix_error (e, fn, f) -> 456 | + prerr_endline ("ocamlfind: " ^ fn ^ " " ^ f 457 | + ^ ": " ^ Unix.error_message e); 458 | + exit 2 459 | | Findlib.No_such_package(pkg,info) -> 460 | prerr_endline ("ocamlfind: Package `" ^ pkg ^ "' not found" ^ 461 | (if info <> "" then " - " ^ info else "")); 462 | --- ./src/findlib/Makefile 463 | +++ ./src/findlib/Makefile 464 | @@ -90,6 +90,7 @@ 465 | cat findlib_config.mlp | \ 466 | $(SH) $(TOP)/tools/patch '@CONFIGFILE@' '$(OCAMLFIND_CONF)' | \ 467 | $(SH) $(TOP)/tools/patch '@STDLIB@' '$(OCAML_CORE_STDLIB)' | \ 468 | + $(SH) $(TOP)/tools/patch '@EXEC_SUFFIX@' '$(EXEC_SUFFIX)' | \ 469 | sed -e 's;@AUTOLINK@;$(OCAML_AUTOLINK);g' \ 470 | -e 's;@SYSTEM@;$(SYSTEM);g' \ 471 | >findlib_config.ml 472 | -------------------------------------------------------------------------------- /esy.lock/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "checksum": "79d0abd6d84736619240761ef6e1efba", 3 | "root": "gh-feed-reader@link-dev:./esy.json", 4 | "node": { 5 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9": { 6 | "id": 7 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 8 | "name": "ocaml", 9 | "version": 10 | "github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb", 11 | "source": { 12 | "type": "install", 13 | "source": [ 14 | "github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb" 15 | ] 16 | }, 17 | "overrides": [], 18 | "dependencies": [], 19 | "devDependencies": [] 20 | }, 21 | "gh-feed-reader@link-dev:./esy.json": { 22 | "id": "gh-feed-reader@link-dev:./esy.json", 23 | "name": "gh-feed-reader", 24 | "version": "link-dev:./esy.json", 25 | "source": { "type": "link-dev", "path": ".", "manifest": "esy.json" }, 26 | "overrides": [], 27 | "dependencies": [ 28 | "bs-platform@github:EduardoRFS/bucklescript#97d478aa2f72ac92b776dfc9a50f316f6a46eefa@d41d8cd9", 29 | "@opam/merlin@opam:4.1-412@a9da5f4b" 30 | ], 31 | "devDependencies": [], 32 | "installConfig": { "pnp": false } 33 | }, 34 | "esy-m4@github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7@d41d8cd9": { 35 | "id": 36 | "esy-m4@github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7@d41d8cd9", 37 | "name": "esy-m4", 38 | "version": 39 | "github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7", 40 | "source": { 41 | "type": "install", 42 | "source": [ 43 | "github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7" 44 | ] 45 | }, 46 | "overrides": [], 47 | "dependencies": [], 48 | "devDependencies": [] 49 | }, 50 | "bs-platform@github:EduardoRFS/bucklescript#97d478aa2f72ac92b776dfc9a50f316f6a46eefa@d41d8cd9": { 51 | "id": 52 | "bs-platform@github:EduardoRFS/bucklescript#97d478aa2f72ac92b776dfc9a50f316f6a46eefa@d41d8cd9", 53 | "name": "bs-platform", 54 | "version": 55 | "github:EduardoRFS/bucklescript#97d478aa2f72ac92b776dfc9a50f316f6a46eefa", 56 | "source": { 57 | "type": "install", 58 | "source": [ 59 | "github:EduardoRFS/bucklescript#97d478aa2f72ac92b776dfc9a50f316f6a46eefa" 60 | ] 61 | }, 62 | "overrides": [], 63 | "dependencies": [ 64 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 65 | "@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/reason@3.7.0@d41d8cd9" 66 | ], 67 | "devDependencies": [] 68 | }, 69 | "@opam/yojson@opam:1.7.0@7056d985": { 70 | "id": "@opam/yojson@opam:1.7.0@7056d985", 71 | "name": "@opam/yojson", 72 | "version": "opam:1.7.0", 73 | "source": { 74 | "type": "install", 75 | "source": [ 76 | "archive:https://opam.ocaml.org/cache/md5/b8/b89d39ca3f8c532abe5f547ad3b8f84d#md5:b89d39ca3f8c532abe5f547ad3b8f84d", 77 | "archive:https://github.com/ocaml-community/yojson/releases/download/1.7.0/yojson-1.7.0.tbz#md5:b89d39ca3f8c532abe5f547ad3b8f84d" 78 | ], 79 | "opam": { 80 | "name": "yojson", 81 | "version": "1.7.0", 82 | "path": "esy.lock/opam/yojson.1.7.0" 83 | } 84 | }, 85 | "overrides": [], 86 | "dependencies": [ 87 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 88 | "@opam/easy-format@opam:1.3.2@0484b3c4", 89 | "@opam/dune@opam:2.8.4@ee414d6c", "@opam/cppo@opam:1.6.7@c28ac3ae", 90 | "@opam/biniou@opam:1.2.1@d7570399", 91 | "@esy-ocaml/substs@0.0.1@d41d8cd9" 92 | ], 93 | "devDependencies": [ 94 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 95 | "@opam/easy-format@opam:1.3.2@0484b3c4", 96 | "@opam/dune@opam:2.8.4@ee414d6c", "@opam/biniou@opam:1.2.1@d7570399" 97 | ] 98 | }, 99 | "@opam/result@opam:1.5@6b753c82": { 100 | "id": "@opam/result@opam:1.5@6b753c82", 101 | "name": "@opam/result", 102 | "version": "opam:1.5", 103 | "source": { 104 | "type": "install", 105 | "source": [ 106 | "archive:https://opam.ocaml.org/cache/md5/1b/1b82dec78849680b49ae9a8a365b831b#md5:1b82dec78849680b49ae9a8a365b831b", 107 | "archive:https://github.com/janestreet/result/releases/download/1.5/result-1.5.tbz#md5:1b82dec78849680b49ae9a8a365b831b" 108 | ], 109 | "opam": { 110 | "name": "result", 111 | "version": "1.5", 112 | "path": "esy.lock/opam/result.1.5" 113 | } 114 | }, 115 | "overrides": [], 116 | "dependencies": [ 117 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 118 | "@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9" 119 | ], 120 | "devDependencies": [ 121 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 122 | "@opam/dune@opam:2.8.4@ee414d6c" 123 | ] 124 | }, 125 | "@opam/ppx_derivers@opam:1.2.1@ecf0aa45": { 126 | "id": "@opam/ppx_derivers@opam:1.2.1@ecf0aa45", 127 | "name": "@opam/ppx_derivers", 128 | "version": "opam:1.2.1", 129 | "source": { 130 | "type": "install", 131 | "source": [ 132 | "archive:https://opam.ocaml.org/cache/md5/5d/5dc2bf130c1db3c731fe0fffc5648b41#md5:5dc2bf130c1db3c731fe0fffc5648b41", 133 | "archive:https://github.com/ocaml-ppx/ppx_derivers/archive/1.2.1.tar.gz#md5:5dc2bf130c1db3c731fe0fffc5648b41" 134 | ], 135 | "opam": { 136 | "name": "ppx_derivers", 137 | "version": "1.2.1", 138 | "path": "esy.lock/opam/ppx_derivers.1.2.1" 139 | } 140 | }, 141 | "overrides": [], 142 | "dependencies": [ 143 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 144 | "@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9" 145 | ], 146 | "devDependencies": [ 147 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 148 | "@opam/dune@opam:2.8.4@ee414d6c" 149 | ] 150 | }, 151 | "@opam/ocamlfind@opam:1.8.1@b7dc3072": { 152 | "id": "@opam/ocamlfind@opam:1.8.1@b7dc3072", 153 | "name": "@opam/ocamlfind", 154 | "version": "opam:1.8.1", 155 | "source": { 156 | "type": "install", 157 | "source": [ 158 | "archive:https://opam.ocaml.org/cache/md5/18/18ca650982c15536616dea0e422cbd8c#md5:18ca650982c15536616dea0e422cbd8c", 159 | "archive:http://download2.camlcity.org/download/findlib-1.8.1.tar.gz#md5:18ca650982c15536616dea0e422cbd8c", 160 | "archive:http://download.camlcity.org/download/findlib-1.8.1.tar.gz#md5:18ca650982c15536616dea0e422cbd8c" 161 | ], 162 | "opam": { 163 | "name": "ocamlfind", 164 | "version": "1.8.1", 165 | "path": "esy.lock/opam/ocamlfind.1.8.1" 166 | } 167 | }, 168 | "overrides": [ 169 | { 170 | "opamoverride": 171 | "esy.lock/overrides/opam__s__ocamlfind_opam__c__1.8.1_opam_override" 172 | } 173 | ], 174 | "dependencies": [ 175 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 176 | "@opam/conf-m4@opam:1@196bf219", "@esy-ocaml/substs@0.0.1@d41d8cd9" 177 | ], 178 | "devDependencies": [ 179 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9" 180 | ] 181 | }, 182 | "@opam/merlin-extend@opam:0.6@404f814c": { 183 | "id": "@opam/merlin-extend@opam:0.6@404f814c", 184 | "name": "@opam/merlin-extend", 185 | "version": "opam:0.6", 186 | "source": { 187 | "type": "install", 188 | "source": [ 189 | "archive:https://opam.ocaml.org/cache/sha256/c2/c2f236ae97feb6ba0bc90f33beb7b7343e42f9871b66de9ba07974917e256c43#sha256:c2f236ae97feb6ba0bc90f33beb7b7343e42f9871b66de9ba07974917e256c43", 190 | "archive:https://github.com/let-def/merlin-extend/releases/download/v0.6/merlin-extend-v0.6.tbz#sha256:c2f236ae97feb6ba0bc90f33beb7b7343e42f9871b66de9ba07974917e256c43" 191 | ], 192 | "opam": { 193 | "name": "merlin-extend", 194 | "version": "0.6", 195 | "path": "esy.lock/opam/merlin-extend.0.6" 196 | } 197 | }, 198 | "overrides": [], 199 | "dependencies": [ 200 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 201 | "@opam/dune@opam:2.8.4@ee414d6c", "@opam/cppo@opam:1.6.7@c28ac3ae", 202 | "@esy-ocaml/substs@0.0.1@d41d8cd9" 203 | ], 204 | "devDependencies": [ 205 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 206 | "@opam/dune@opam:2.8.4@ee414d6c" 207 | ] 208 | }, 209 | "@opam/merlin@opam:4.1-412@a9da5f4b": { 210 | "id": "@opam/merlin@opam:4.1-412@a9da5f4b", 211 | "name": "@opam/merlin", 212 | "version": "opam:4.1-412", 213 | "source": { 214 | "type": "install", 215 | "source": [ 216 | "archive:https://opam.ocaml.org/cache/sha256/fb/fb4caede73bdb8393bd60e31792af74b901ae2d319ac2f2a2252c694d2069d8d#sha256:fb4caede73bdb8393bd60e31792af74b901ae2d319ac2f2a2252c694d2069d8d", 217 | "archive:https://github.com/ocaml/merlin/releases/download/v4.1-412/merlin-v4.1-412.tbz#sha256:fb4caede73bdb8393bd60e31792af74b901ae2d319ac2f2a2252c694d2069d8d" 218 | ], 219 | "opam": { 220 | "name": "merlin", 221 | "version": "4.1-412", 222 | "path": "esy.lock/opam/merlin.4.1-412" 223 | } 224 | }, 225 | "overrides": [], 226 | "dependencies": [ 227 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 228 | "@opam/yojson@opam:1.7.0@7056d985", "@opam/result@opam:1.5@6b753c82", 229 | "@opam/dune@opam:2.8.4@ee414d6c", 230 | "@opam/dot-merlin-reader@opam:4.1@120afa42", 231 | "@opam/csexp@opam:1.4.0@bd1cb034", "@esy-ocaml/substs@0.0.1@d41d8cd9" 232 | ], 233 | "devDependencies": [ 234 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 235 | "@opam/yojson@opam:1.7.0@7056d985", "@opam/result@opam:1.5@6b753c82", 236 | "@opam/dune@opam:2.8.4@ee414d6c", 237 | "@opam/dot-merlin-reader@opam:4.1@120afa42", 238 | "@opam/csexp@opam:1.4.0@bd1cb034" 239 | ] 240 | }, 241 | "@opam/menhirSdk@opam:20210310@5abaafca": { 242 | "id": "@opam/menhirSdk@opam:20210310@5abaafca", 243 | "name": "@opam/menhirSdk", 244 | "version": "opam:20210310", 245 | "source": { 246 | "type": "install", 247 | "source": [ 248 | "archive:https://opam.ocaml.org/cache/md5/1c/1cbc71c0bc1f3ddc3e71d5c1f919fd1a#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a", 249 | "archive:https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a" 250 | ], 251 | "opam": { 252 | "name": "menhirSdk", 253 | "version": "20210310", 254 | "path": "esy.lock/opam/menhirSdk.20210310" 255 | } 256 | }, 257 | "overrides": [], 258 | "dependencies": [ 259 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 260 | "@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9" 261 | ], 262 | "devDependencies": [ 263 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 264 | "@opam/dune@opam:2.8.4@ee414d6c" 265 | ] 266 | }, 267 | "@opam/menhirLib@opam:20210310@f9315713": { 268 | "id": "@opam/menhirLib@opam:20210310@f9315713", 269 | "name": "@opam/menhirLib", 270 | "version": "opam:20210310", 271 | "source": { 272 | "type": "install", 273 | "source": [ 274 | "archive:https://opam.ocaml.org/cache/md5/1c/1cbc71c0bc1f3ddc3e71d5c1f919fd1a#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a", 275 | "archive:https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a" 276 | ], 277 | "opam": { 278 | "name": "menhirLib", 279 | "version": "20210310", 280 | "path": "esy.lock/opam/menhirLib.20210310" 281 | } 282 | }, 283 | "overrides": [], 284 | "dependencies": [ 285 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 286 | "@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9" 287 | ], 288 | "devDependencies": [ 289 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 290 | "@opam/dune@opam:2.8.4@ee414d6c" 291 | ] 292 | }, 293 | "@opam/menhir@opam:20210310@50de9216": { 294 | "id": "@opam/menhir@opam:20210310@50de9216", 295 | "name": "@opam/menhir", 296 | "version": "opam:20210310", 297 | "source": { 298 | "type": "install", 299 | "source": [ 300 | "archive:https://opam.ocaml.org/cache/md5/1c/1cbc71c0bc1f3ddc3e71d5c1f919fd1a#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a", 301 | "archive:https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a" 302 | ], 303 | "opam": { 304 | "name": "menhir", 305 | "version": "20210310", 306 | "path": "esy.lock/opam/menhir.20210310" 307 | } 308 | }, 309 | "overrides": [], 310 | "dependencies": [ 311 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 312 | "@opam/menhirSdk@opam:20210310@5abaafca", 313 | "@opam/menhirLib@opam:20210310@f9315713", 314 | "@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9" 315 | ], 316 | "devDependencies": [ 317 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 318 | "@opam/menhirSdk@opam:20210310@5abaafca", 319 | "@opam/menhirLib@opam:20210310@f9315713", 320 | "@opam/dune@opam:2.8.4@ee414d6c" 321 | ] 322 | }, 323 | "@opam/fix@opam:20201120@5c318621": { 324 | "id": "@opam/fix@opam:20201120@5c318621", 325 | "name": "@opam/fix", 326 | "version": "opam:20201120", 327 | "source": { 328 | "type": "install", 329 | "source": [ 330 | "archive:https://opam.ocaml.org/cache/md5/7e/7eb570b759635fe66f3556d2b1cc88e3#md5:7eb570b759635fe66f3556d2b1cc88e3", 331 | "archive:https://gitlab.inria.fr/fpottier/fix/repository/20201120/archive.tar.gz#md5:7eb570b759635fe66f3556d2b1cc88e3" 332 | ], 333 | "opam": { 334 | "name": "fix", 335 | "version": "20201120", 336 | "path": "esy.lock/opam/fix.20201120" 337 | } 338 | }, 339 | "overrides": [], 340 | "dependencies": [ 341 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 342 | "@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9" 343 | ], 344 | "devDependencies": [ 345 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 346 | "@opam/dune@opam:2.8.4@ee414d6c" 347 | ] 348 | }, 349 | "@opam/easy-format@opam:1.3.2@0484b3c4": { 350 | "id": "@opam/easy-format@opam:1.3.2@0484b3c4", 351 | "name": "@opam/easy-format", 352 | "version": "opam:1.3.2", 353 | "source": { 354 | "type": "install", 355 | "source": [ 356 | "archive:https://opam.ocaml.org/cache/sha256/34/3440c2b882d537ae5e9011eb06abb53f5667e651ea4bb3b460ea8230fa8c1926#sha256:3440c2b882d537ae5e9011eb06abb53f5667e651ea4bb3b460ea8230fa8c1926", 357 | "archive:https://github.com/mjambon/easy-format/releases/download/1.3.2/easy-format-1.3.2.tbz#sha256:3440c2b882d537ae5e9011eb06abb53f5667e651ea4bb3b460ea8230fa8c1926" 358 | ], 359 | "opam": { 360 | "name": "easy-format", 361 | "version": "1.3.2", 362 | "path": "esy.lock/opam/easy-format.1.3.2" 363 | } 364 | }, 365 | "overrides": [], 366 | "dependencies": [ 367 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 368 | "@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9" 369 | ], 370 | "devDependencies": [ 371 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 372 | "@opam/dune@opam:2.8.4@ee414d6c" 373 | ] 374 | }, 375 | "@opam/dune@opam:2.8.4@ee414d6c": { 376 | "id": "@opam/dune@opam:2.8.4@ee414d6c", 377 | "name": "@opam/dune", 378 | "version": "opam:2.8.4", 379 | "source": { 380 | "type": "install", 381 | "source": [ 382 | "archive:https://opam.ocaml.org/cache/sha256/4e/4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac", 383 | "archive:https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac" 384 | ], 385 | "opam": { 386 | "name": "dune", 387 | "version": "2.8.4", 388 | "path": "esy.lock/opam/dune.2.8.4" 389 | } 390 | }, 391 | "overrides": [], 392 | "dependencies": [ 393 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 394 | "@opam/base-unix@opam:base@87d0b2eb", 395 | "@opam/base-threads@opam:base@36803084", 396 | "@esy-ocaml/substs@0.0.1@d41d8cd9" 397 | ], 398 | "devDependencies": [ 399 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 400 | "@opam/base-unix@opam:base@87d0b2eb", 401 | "@opam/base-threads@opam:base@36803084" 402 | ] 403 | }, 404 | "@opam/dot-merlin-reader@opam:4.1@120afa42": { 405 | "id": "@opam/dot-merlin-reader@opam:4.1@120afa42", 406 | "name": "@opam/dot-merlin-reader", 407 | "version": "opam:4.1", 408 | "source": { 409 | "type": "install", 410 | "source": [ 411 | "archive:https://opam.ocaml.org/cache/sha256/14/14a36d6fb8646a5df4530420a7861722f1a4ee04753717947305e3676031e7cd#sha256:14a36d6fb8646a5df4530420a7861722f1a4ee04753717947305e3676031e7cd", 412 | "archive:https://github.com/ocaml/merlin/releases/download/v4.1/dot-merlin-reader-v4.1.tbz#sha256:14a36d6fb8646a5df4530420a7861722f1a4ee04753717947305e3676031e7cd" 413 | ], 414 | "opam": { 415 | "name": "dot-merlin-reader", 416 | "version": "4.1", 417 | "path": "esy.lock/opam/dot-merlin-reader.4.1" 418 | } 419 | }, 420 | "overrides": [], 421 | "dependencies": [ 422 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 423 | "@opam/yojson@opam:1.7.0@7056d985", "@opam/result@opam:1.5@6b753c82", 424 | "@opam/ocamlfind@opam:1.8.1@b7dc3072", 425 | "@opam/dune@opam:2.8.4@ee414d6c", "@opam/csexp@opam:1.4.0@bd1cb034", 426 | "@esy-ocaml/substs@0.0.1@d41d8cd9" 427 | ], 428 | "devDependencies": [ 429 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 430 | "@opam/yojson@opam:1.7.0@7056d985", "@opam/result@opam:1.5@6b753c82", 431 | "@opam/ocamlfind@opam:1.8.1@b7dc3072", 432 | "@opam/dune@opam:2.8.4@ee414d6c", "@opam/csexp@opam:1.4.0@bd1cb034" 433 | ] 434 | }, 435 | "@opam/csexp@opam:1.4.0@bd1cb034": { 436 | "id": "@opam/csexp@opam:1.4.0@bd1cb034", 437 | "name": "@opam/csexp", 438 | "version": "opam:1.4.0", 439 | "source": { 440 | "type": "install", 441 | "source": [ 442 | "archive:https://opam.ocaml.org/cache/sha256/8e/8e3d6fca87f102a126dee8b72a2a0d146f10439c47218dfc149d51bf3edf364e#sha256:8e3d6fca87f102a126dee8b72a2a0d146f10439c47218dfc149d51bf3edf364e", 443 | "archive:https://github.com/ocaml-dune/csexp/releases/download/1.4.0/csexp-1.4.0.tbz#sha256:8e3d6fca87f102a126dee8b72a2a0d146f10439c47218dfc149d51bf3edf364e" 444 | ], 445 | "opam": { 446 | "name": "csexp", 447 | "version": "1.4.0", 448 | "path": "esy.lock/opam/csexp.1.4.0" 449 | } 450 | }, 451 | "overrides": [], 452 | "dependencies": [ 453 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 454 | "@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.4@ee414d6c", 455 | "@esy-ocaml/substs@0.0.1@d41d8cd9" 456 | ], 457 | "devDependencies": [ 458 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 459 | "@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.4@ee414d6c" 460 | ] 461 | }, 462 | "@opam/cppo@opam:1.6.7@c28ac3ae": { 463 | "id": "@opam/cppo@opam:1.6.7@c28ac3ae", 464 | "name": "@opam/cppo", 465 | "version": "opam:1.6.7", 466 | "source": { 467 | "type": "install", 468 | "source": [ 469 | "archive:https://opam.ocaml.org/cache/sha256/db/db553e3e6c206df09b1858c3aef5e21e56564d593642a3c78bcedb6af36f529d#sha256:db553e3e6c206df09b1858c3aef5e21e56564d593642a3c78bcedb6af36f529d", 470 | "archive:https://github.com/ocaml-community/cppo/releases/download/v1.6.7/cppo-v1.6.7.tbz#sha256:db553e3e6c206df09b1858c3aef5e21e56564d593642a3c78bcedb6af36f529d" 471 | ], 472 | "opam": { 473 | "name": "cppo", 474 | "version": "1.6.7", 475 | "path": "esy.lock/opam/cppo.1.6.7" 476 | } 477 | }, 478 | "overrides": [], 479 | "dependencies": [ 480 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 481 | "@opam/dune@opam:2.8.4@ee414d6c", 482 | "@opam/base-unix@opam:base@87d0b2eb", 483 | "@esy-ocaml/substs@0.0.1@d41d8cd9" 484 | ], 485 | "devDependencies": [ 486 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 487 | "@opam/dune@opam:2.8.4@ee414d6c", 488 | "@opam/base-unix@opam:base@87d0b2eb" 489 | ] 490 | }, 491 | "@opam/conf-m4@opam:1@196bf219": { 492 | "id": "@opam/conf-m4@opam:1@196bf219", 493 | "name": "@opam/conf-m4", 494 | "version": "opam:1", 495 | "source": { 496 | "type": "install", 497 | "source": [ "no-source:" ], 498 | "opam": { 499 | "name": "conf-m4", 500 | "version": "1", 501 | "path": "esy.lock/opam/conf-m4.1" 502 | } 503 | }, 504 | "overrides": [ 505 | { 506 | "opamoverride": 507 | "esy.lock/overrides/opam__s__conf_m4_opam__c__1_opam_override" 508 | } 509 | ], 510 | "dependencies": [ 511 | "esy-m4@github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7@d41d8cd9", 512 | "@esy-ocaml/substs@0.0.1@d41d8cd9" 513 | ], 514 | "devDependencies": [] 515 | }, 516 | "@opam/biniou@opam:1.2.1@d7570399": { 517 | "id": "@opam/biniou@opam:1.2.1@d7570399", 518 | "name": "@opam/biniou", 519 | "version": "opam:1.2.1", 520 | "source": { 521 | "type": "install", 522 | "source": [ 523 | "archive:https://opam.ocaml.org/cache/sha256/35/35546c68b1929a8e6d27a3b39ecd17b38303a0d47e65eb9d1480c2061ea84335#sha256:35546c68b1929a8e6d27a3b39ecd17b38303a0d47e65eb9d1480c2061ea84335", 524 | "archive:https://github.com/mjambon/biniou/releases/download/1.2.1/biniou-1.2.1.tbz#sha256:35546c68b1929a8e6d27a3b39ecd17b38303a0d47e65eb9d1480c2061ea84335" 525 | ], 526 | "opam": { 527 | "name": "biniou", 528 | "version": "1.2.1", 529 | "path": "esy.lock/opam/biniou.1.2.1" 530 | } 531 | }, 532 | "overrides": [], 533 | "dependencies": [ 534 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 535 | "@opam/easy-format@opam:1.3.2@0484b3c4", 536 | "@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9" 537 | ], 538 | "devDependencies": [ 539 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 540 | "@opam/easy-format@opam:1.3.2@0484b3c4", 541 | "@opam/dune@opam:2.8.4@ee414d6c" 542 | ] 543 | }, 544 | "@opam/base-unix@opam:base@87d0b2eb": { 545 | "id": "@opam/base-unix@opam:base@87d0b2eb", 546 | "name": "@opam/base-unix", 547 | "version": "opam:base", 548 | "source": { 549 | "type": "install", 550 | "source": [ "no-source:" ], 551 | "opam": { 552 | "name": "base-unix", 553 | "version": "base", 554 | "path": "esy.lock/opam/base-unix.base" 555 | } 556 | }, 557 | "overrides": [], 558 | "dependencies": [ "@esy-ocaml/substs@0.0.1@d41d8cd9" ], 559 | "devDependencies": [] 560 | }, 561 | "@opam/base-threads@opam:base@36803084": { 562 | "id": "@opam/base-threads@opam:base@36803084", 563 | "name": "@opam/base-threads", 564 | "version": "opam:base", 565 | "source": { 566 | "type": "install", 567 | "source": [ "no-source:" ], 568 | "opam": { 569 | "name": "base-threads", 570 | "version": "base", 571 | "path": "esy.lock/opam/base-threads.base" 572 | } 573 | }, 574 | "overrides": [], 575 | "dependencies": [ "@esy-ocaml/substs@0.0.1@d41d8cd9" ], 576 | "devDependencies": [] 577 | }, 578 | "@esy-ocaml/substs@0.0.1@d41d8cd9": { 579 | "id": "@esy-ocaml/substs@0.0.1@d41d8cd9", 580 | "name": "@esy-ocaml/substs", 581 | "version": "0.0.1", 582 | "source": { 583 | "type": "install", 584 | "source": [ 585 | "archive:https://registry.npmjs.org/@esy-ocaml/substs/-/substs-0.0.1.tgz#sha1:59ebdbbaedcda123fc7ed8fb2b302b7d819e9a46" 586 | ] 587 | }, 588 | "overrides": [], 589 | "dependencies": [], 590 | "devDependencies": [] 591 | }, 592 | "@esy-ocaml/reason@3.7.0@d41d8cd9": { 593 | "id": "@esy-ocaml/reason@3.7.0@d41d8cd9", 594 | "name": "@esy-ocaml/reason", 595 | "version": "3.7.0", 596 | "source": { 597 | "type": "install", 598 | "source": [ 599 | "archive:https://registry.npmjs.org/@esy-ocaml/reason/-/reason-3.7.0.tgz#sha1:36f92c1c854477c4da37e4769a045ffe60e4fb10" 600 | ] 601 | }, 602 | "overrides": [], 603 | "dependencies": [ 604 | "ocaml@github:anmonteiro/ocaml#72babec0e1796ce322464afc8ef2a0d7125d60cb@d41d8cd9", 605 | "@opam/result@opam:1.5@6b753c82", 606 | "@opam/ppx_derivers@opam:1.2.1@ecf0aa45", 607 | "@opam/ocamlfind@opam:1.8.1@b7dc3072", 608 | "@opam/merlin-extend@opam:0.6@404f814c", 609 | "@opam/menhir@opam:20210310@50de9216", 610 | "@opam/fix@opam:20201120@5c318621", "@opam/dune@opam:2.8.4@ee414d6c" 611 | ], 612 | "devDependencies": [] 613 | } 614 | } 615 | } --------------------------------------------------------------------------------