diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f649d95..3f83f65 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,6 +41,7 @@ jobs: - name: Use OCaml ${{ matrix.ocaml-compiler }} uses: ocaml/setup-ocaml@v2 with: + cache-prefix: v2 ocaml-compiler: ${{ matrix.ocaml-compiler }} opam-depext-flags: --with-test opam-local-packages: | @@ -49,14 +50,16 @@ jobs: - run: opam install "${{ matrix.package }}" --with-test - build-node: + build-melange: strategy: fail-fast: false matrix: os: - ubuntu-latest - node-version: - - 16.x + ocaml-compiler: + - 5.1.x + package: + - melange-decoders runs-on: ${{ matrix.os }} @@ -66,9 +69,20 @@ jobs: - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} + node-version: 16.x cache: 'npm' - run: npm ci - - run: npm run build - - run: npm test + + - name: Use OCaml ${{ matrix.ocaml-compiler }} + uses: ocaml/setup-ocaml@v2 + with: + ocaml-compiler: ${{ matrix.ocaml-compiler }} + opam-depext-flags: --with-test + opam-local-packages: | + decoders.opam + ${{ matrix.package }}.opam + + - run: opam install "${{ matrix.package }}" --with-test + - run: opam exec -- dune build @melange + - run: npx jest diff --git a/Makefile b/Makefile index d9ccc5c..437e303 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ .PHONY: all -all: build test build-bs test-bs +all: build test build-bs test-bs test-mel .PHONY: clean-all clean-all: clean clean-bs @@ -34,9 +34,9 @@ clean: _opam: opam switch create . --empty - opam install -y ocaml-base-compiler.4.12.0 utop ocaml-lsp-server install-dependencies: _opam + opam switch set-invariant ocaml-base-compiler.5.1.1 opam install . --deps-only --with-test DOCS_WORKTREE_PATH=../ocaml-decoders-doc @@ -61,11 +61,11 @@ build-bs: test-bs: npm test -watch-build-bs: - npm run build-watch - -watch-test-bs: - npm run test-watch - clean-bs: npm run clean + +build-mel: + dune build @melange + +test-mel: + npx jest _build/default/out/ diff --git a/__tests__/decoders_bs_json_test.ml b/__tests__/decoders_js_json_test.ml similarity index 96% rename from __tests__/decoders_bs_json_test.ml rename to __tests__/decoders_js_json_test.ml index bfae460..330b515 100644 --- a/__tests__/decoders_bs_json_test.ml +++ b/__tests__/decoders_js_json_test.ml @@ -1,7 +1,7 @@ open Jest -open Bs_json +open Js_json -external parse_int : string -> int = "parseInt" [@@bs.scope "window"] [@@bs.val] +external parse_int : string -> int = "parseInt" [@@mel.scope "window"] [@@mel.val] let () = describe diff --git a/__tests__/decoders_bs_xml_test.ml b/__tests__/decoders_js_xml_test.ml similarity index 99% rename from __tests__/decoders_bs_xml_test.ml rename to __tests__/decoders_js_xml_test.ml index d6610ef..e3c80f1 100644 --- a/__tests__/decoders_bs_xml_test.ml +++ b/__tests__/decoders_js_xml_test.ml @@ -1,5 +1,5 @@ open Jest -open Bs_xml +open Js_xml let () = describe diff --git a/__tests__/dune b/__tests__/dune new file mode 100644 index 0000000..df358b6 --- /dev/null +++ b/__tests__/dune @@ -0,0 +1,11 @@ +(subdir + melange + (library + (name decoders_tests_melange) + (modes melange) + (libraries decoders_mel melange-jest.jest) + (preprocess (pps melange.ppx)) + (flags -open Decoders_mel) + (wrapped false)) + (copy_files# "../*.ml") + (copy_files# "../*.re")) diff --git a/bsconfig.json b/bsconfig.json index 742c0c8..52c0cb6 100644 --- a/bsconfig.json +++ b/bsconfig.json @@ -18,7 +18,10 @@ "xml.ml" ] }, { - "dir" : "src-bs" + "dir" : "src-js", + "files": { + "excludes": ["decoders_mel.ml"] + } }, { "dir": "__tests__", "type": "dev" diff --git a/decoders-bencode.opam b/decoders-bencode.opam index bfc0e21..1865743 100644 --- a/decoders-bencode.opam +++ b/decoders-bencode.opam @@ -10,7 +10,7 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.03.0"} "decoders" {= version} "bencode" {>= "2.0"} diff --git a/decoders-cbor.opam b/decoders-cbor.opam index 50535eb..8d5779a 100644 --- a/decoders-cbor.opam +++ b/decoders-cbor.opam @@ -10,7 +10,7 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.03.0"} "decoders" {= version} "cbor" diff --git a/decoders-ezjsonm.opam b/decoders-ezjsonm.opam index d0e0485..840720c 100644 --- a/decoders-ezjsonm.opam +++ b/decoders-ezjsonm.opam @@ -10,7 +10,7 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.03.0"} "decoders" {= version} "ezjsonm" {>= "0.4.0"} diff --git a/decoders-ezxmlm.opam b/decoders-ezxmlm.opam index c5073d8..640fefa 100644 --- a/decoders-ezxmlm.opam +++ b/decoders-ezxmlm.opam @@ -10,7 +10,7 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.03.0"} "decoders" {= version} "ezxmlm" {>= "1.1.0"} diff --git a/decoders-jsonaf.opam b/decoders-jsonaf.opam index 4a88fbb..af0253e 100644 --- a/decoders-jsonaf.opam +++ b/decoders-jsonaf.opam @@ -12,7 +12,7 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.10.0"} "decoders" {= version} "jsonaf" {>= "0.15.0"} diff --git a/decoders-jsonm.opam b/decoders-jsonm.opam index 7b398f8..ef57e19 100644 --- a/decoders-jsonm.opam +++ b/decoders-jsonm.opam @@ -10,7 +10,7 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.03.0"} "decoders" {= version} "jsonm" diff --git a/decoders-msgpck.opam b/decoders-msgpck.opam index 6ac7f13..e6e503c 100644 --- a/decoders-msgpck.opam +++ b/decoders-msgpck.opam @@ -12,7 +12,7 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.03.0"} "decoders" {= version} "msgpck" {>= "1.3"} diff --git a/decoders-sexplib.opam b/decoders-sexplib.opam index d1487c5..f862b9b 100644 --- a/decoders-sexplib.opam +++ b/decoders-sexplib.opam @@ -10,7 +10,7 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.03.0"} "decoders" {= version} "sexplib0" diff --git a/decoders-yojson.opam b/decoders-yojson.opam index 44c5f3f..d7cc6f6 100644 --- a/decoders-yojson.opam +++ b/decoders-yojson.opam @@ -10,7 +10,7 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.03.0"} "decoders" {= version} "yojson" {>= "1.6.0"} diff --git a/decoders.opam b/decoders.opam index c5ade6f..4c1374c 100644 --- a/decoders.opam +++ b/decoders.opam @@ -10,9 +10,10 @@ homepage: "https://github.com/mattjbray/ocaml-decoders" doc: "https://mattjbray.github.io/ocaml-decoders/" bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" depends: [ - "dune" {>= "3.1"} + "dune" {>= "3.8"} "ocaml" {>= "4.03.0"} "odoc" {with-doc} + "melange" "containers" {with-test & >= "0.16"} ] build: [ diff --git a/dune b/dune index 8765da5..fb3bfb7 100644 --- a/dune +++ b/dune @@ -1 +1,6 @@ -(dirs :standard \ node_modules) +(dirs :standard __tests__ \ node_modules) + +(melange.emit + (target out) + (preprocess (pps melange.ppx)) + (libraries decoders_mel decoders_tests_melange)) diff --git a/dune-project b/dune-project index 1ff060a..bf122b6 100644 --- a/dune-project +++ b/dune-project @@ -1,4 +1,5 @@ -(lang dune 3.1) +(lang dune 3.8) +(using melange 0.1) (name decoders) (generate_opam_files true) (license ISC) @@ -135,4 +136,21 @@ (depends (ocaml (>= 4.03.0)) (odoc :with-doc) + melange (containers (and :with-test (>= 0.16))))) + +;; melange lib convention is to put `melange-` as the prefix, rather than the +;; suffix, which unfortunately contradicts the `decoders-` prefix convention +(package + (name melange-decoders) + (synopsis "Melange backend for decoders") + (description + "A combinator library for \"decoding\" JSON-like values into your own Ocaml types, inspired by Elm's `Json.Decode` and `Json.Encode`.") + (depends + (ocaml (>= 4.14.1)) + (odoc :with-doc) + (decoders (= :version)) + (melange (>= 3.0.0)) + (melange-fetch :with-test) + (melange-jest :with-test) + (melange-webapi :with-test))) diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..486c4d9 --- /dev/null +++ b/flake.lock @@ -0,0 +1,60 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1688392541, + "narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-22.11", + "type": "indirect" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..ec4936b --- /dev/null +++ b/flake.nix @@ -0,0 +1,11 @@ +{ + inputs = { + nixpkgs.url = "nixpkgs/nixos-22.11"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }@attrs: + flake-utils.lib.eachDefaultSystem (system: + let pkgs = nixpkgs.legacyPackages.${system}; + in { devShells.default = import ./shell.nix { inherit pkgs; }; }); +} diff --git a/melange-decoders.opam b/melange-decoders.opam new file mode 100644 index 0000000..0397380 --- /dev/null +++ b/melange-decoders.opam @@ -0,0 +1,36 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "Melange backend for decoders" +description: + "A combinator library for \"decoding\" JSON-like values into your own Ocaml types, inspired by Elm's `Json.Decode` and `Json.Encode`." +maintainer: ["Matt Bray "] +authors: ["Matt Bray "] +license: "ISC" +homepage: "https://github.com/mattjbray/ocaml-decoders" +doc: "https://mattjbray.github.io/ocaml-decoders/" +bug-reports: "https://github.com/mattjbray/ocaml-decoders/issues" +depends: [ + "dune" {>= "3.8"} + "ocaml" {>= "4.14.1"} + "odoc" {with-doc} + "decoders" {= version} + "melange" {>= "3.0.0"} + "melange-fetch" {with-test} + "melange-jest" {with-test} + "melange-webapi" {with-test} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/mattjbray/ocaml-decoders.git" diff --git a/package.json b/package.json index 7f4eddf..32c6f1e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "build": "bsb -make-world", "build-watch": "bsb -make-world -w", "test": "bsb -make-world && jest", - "test-watch": "jest --watch", "clean": "bsb -clean-world" }, "repository": { diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..6f5b441 --- /dev/null +++ b/shell.nix @@ -0,0 +1,9 @@ +{ pkgs ? import { } }: +pkgs.mkShell { + buildInputs = + [ pkgs.opam pkgs.pkg-config pkgs.gmp pkgs.zlib ] + ++ (if pkgs.stdenv.isDarwin then + (with pkgs.darwin.apple_sdk.frameworks; [ CoreServices Foundation ]) + else + [ pkgs.inotify-tools ]); +} diff --git a/src-js/dune b/src-js/dune new file mode 100644 index 0000000..7bc5b63 --- /dev/null +++ b/src-js/dune @@ -0,0 +1,6 @@ +(library + (name decoders_mel) + (public_name melange-decoders) + (preprocess (pps melange.ppx)) + (modes melange) + (libraries decoders melange.dom melange.belt)) diff --git a/src-bs/bs_json.ml b/src-js/js_json.ml similarity index 93% rename from src-bs/bs_json.ml rename to src-js/js_json.ml index ddbb981..b2547de 100644 --- a/src-bs/bs_json.ml +++ b/src-js/js_json.ml @@ -70,10 +70,10 @@ module Decode = struct let oks, errs = arr |> Js.Array.reducei - (fun (oks, errs) x i -> + ~f:(fun (oks, errs) x i -> match decoder.dec x with | Ok a -> - let _ = Js.Array.push a oks in + let _ = Js.Array.push ~value:a oks in (oks, errs) | Error e -> let _ = @@ -82,7 +82,7 @@ module Decode = struct errs in (oks, errs) ) - ([||], [||]) + ~init:([||], [||]) in if Js.Array.length errs > 0 then @@ -123,5 +123,5 @@ module Encode = struct include Encode.Make (Json_encodeable) let array encoder xs = - xs |> Js.Array.map (fun x -> encoder x) |> Js.Json.array + xs |> Js.Array.map ~f:(fun x -> encoder x) |> Js.Json.array end diff --git a/src-bs/bs_json.mli b/src-js/js_json.mli similarity index 100% rename from src-bs/bs_json.mli rename to src-js/js_json.mli diff --git a/src-bs/bs_xml.ml b/src-js/js_xml.ml similarity index 90% rename from src-bs/bs_xml.ml rename to src-js/js_xml.ml index a1684d4..fe6ee78 100644 --- a/src-bs/bs_xml.ml +++ b/src-js/js_xml.ml @@ -1,21 +1,21 @@ module DOMParser = struct type t - external create : unit -> t = "DOMParser" [@@bs.new] + external create : unit -> t = "DOMParser" [@@mel.new] external parseFromString : t -> string -> string -> Dom.element = "parseFromString" - [@@bs.send] + [@@mel.send] external firstElementChildUnsafe : Dom.element -> Dom.element = "firstElementChild" - [@@bs.get] + [@@mel.get] external querySelector : - Dom.element -> string -> Dom.element Js.null_undefined = "querySelector" - [@@bs.send] + Dom.element -> string -> Dom.element Js.nullable = "querySelector" + [@@mel.send] - external textContent : Dom.element -> string = "textContent" [@@bs.get] + external textContent : Dom.element -> string = "textContent" [@@mel.get] let parse_xml text = let parser = create () in @@ -30,13 +30,13 @@ end module Node = struct (* See https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType *) - external element_node : int = "ELEMENT_NODE" [@@bs.val] [@@bs.scope "Node"] + external element_node : int = "ELEMENT_NODE" [@@mel.scope "Node"] - external text_node : int = "TEXT_NODE" [@@bs.val] [@@bs.scope "Node"] + external text_node : int = "TEXT_NODE" [@@mel.scope "Node"] - external comment_node : int = "COMMENT_NODE" [@@bs.val] [@@bs.scope "Node"] + external comment_node : int = "COMMENT_NODE" [@@mel.scope "Node"] - external nodeType : Dom.node -> int = "nodeType" [@@bs.get] + external nodeType : Dom.node -> int = "nodeType" [@@mel.get] external of_element : Dom.element -> Dom.node = "%identity" @@ -72,23 +72,23 @@ module Node_list = struct end module Text = struct - external data : Dom.text -> string = "data" [@@bs.get] + external data : Dom.text -> string = "data" [@@mel.get] end module Element = struct - external childNodes : Dom.element -> Dom.nodeList = "childNodes" [@@bs.get] + external childNodes : Dom.element -> Dom.nodeList = "childNodes" [@@mel.get] let child_nodes elt = childNodes elt |> Node_list.to_array |> Array.to_list - external tagName : Dom.element -> string = "tagName" [@@bs.get] + external tagName : Dom.element -> string = "tagName" [@@mel.get] external getAttribute : Dom.element -> string -> string Js.Nullable.t = "getAttribute" - [@@bs.send] + [@@mel.send] external getAttributeNames : Dom.element -> string Js.Array.t = "getAttributeNames" - [@@bs.send] + [@@mel.send] let get_attribute elt attr = let v = getAttribute elt attr in @@ -96,28 +96,28 @@ module Element = struct external append : Dom.element -> Dom.node array -> unit = "append" - [@@bs.send] [@@variadic] + [@@mel.send] [@@mel.variadic] external setAttribute : Dom.element -> string -> string -> unit = "setAttribute" - [@@bs.send] + [@@mel.send] end module XMLSerializer = struct type t - external create : unit -> t = "XMLSerializer" [@@bs.new] + external create : unit -> t = "XMLSerializer" [@@mel.new] external serializeToString : t -> Dom.node -> string = "serializeToString" - [@@bs.send] + [@@mel.send] end module Document = struct external createElementNS : string -> string -> Dom.element = "createElementNS" - [@@val] [@@scope "window", "document"] + [@@mel.scope "window", "document"] external createTextNode : string -> Dom.text = "createTextNode" - [@@val] [@@scope "window", "document"] + [@@mel.scope "window", "document"] end module Encode = struct diff --git a/src-bs/bs_xml.mli b/src-js/js_xml.mli similarity index 100% rename from src-bs/bs_xml.mli rename to src-js/js_xml.mli diff --git a/src-bs/shims_let_ops_.ml b/src-js/shims_let_ops_.ml similarity index 100% rename from src-bs/shims_let_ops_.ml rename to src-js/shims_let_ops_.ml diff --git a/src-bs/util.ml b/src-js/util.ml similarity index 100% rename from src-bs/util.ml rename to src-js/util.ml diff --git a/src-bs/util.mli b/src-js/util.mli similarity index 100% rename from src-bs/util.mli rename to src-js/util.mli diff --git a/src/dune b/src/dune index e60d8a2..11ee2b6 100644 --- a/src/dune +++ b/src/dune @@ -1,7 +1,8 @@ (library (name decoders) (flags :standard -warn-error -a+8) - (public_name decoders)) + (public_name decoders) + (modes :standard melange)) (rule (targets shims_let_ops_.ml)