Skip to content

Commit

Permalink
Merge pull request #10 from melange-community/ppx
Browse files Browse the repository at this point in the history
Port ppx from andreypopp/ppx_deriving
  • Loading branch information
jchavarri authored Aug 16, 2024
2 parents 55a301a + 19fcb09 commit c615cb1
Show file tree
Hide file tree
Showing 27 changed files with 4,058 additions and 87 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: main

on:
pull_request:
push:
schedule:
- cron: 0 1 * * MON

permissions: read-all

jobs:
build:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
ocaml-compiler:
- "4.14"
- "5.1"
- "5.2"

runs-on: ${{ matrix.os }}

steps:
- name: checkout tree
uses: actions/checkout@v4

- name: set-up OCaml ${{ matrix.ocaml-compiler }}
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: ${{ matrix.ocaml-compiler }}
opam-repositories: |
default: https://github.com/ocaml/opam-repository.git
- run: opam install . --deps-only --with-test

- run: opam exec -- dune build

- run: opam exec -- dune runtest
2 changes: 1 addition & 1 deletion .github/workflows/nix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ocamlVersion: [5_1]
ocamlVersion: [5_2]
steps:
- uses: actions/checkout@v2
- uses: cachix/install-nix-action@v21
Expand Down
3 changes: 3 additions & 0 deletions .ocamlformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
break-infix=fit-or-vertical
margin=74
parens-tuple=multi-line-only
8 changes: 7 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
## Unreleased

- Port PPX from @andreypopp/ppx_deriving_json
([#10](https://github.com/melange-community/melange-json/pull/10))

## 1.1.0 (2024-02-03)

- Require Melange v3 ([#6](https://github.com/melange-community/melange-json/pull/6))
- Require Melange v3
([#6](https://github.com/melange-community/melange-json/pull/6))

## 1.0.0 (2023-10-09)

Expand Down
121 changes: 120 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# melange-json

Compositional JSON encode/decode library for BuckleScript.
Compositional JSON encode/decode library and PPX for
[Melange](https://melange.re/).

Based on [@glennsl/bs-json](https://github.com/glennsl/bs-json).

Expand Down Expand Up @@ -146,6 +147,124 @@ let floatPoint = point(Json.Decode.float);
Encoders work exactly the same way, just in reverse. `'a encoder` is just an alias for `'a -> Js.Json.t`, and this also
transfers to composition: `'a encoder -> 'a array encoder` expands to `('a -> Js.Json.t) -> 'a array -> Js.Json.t`.

## PPX

A [ppx deriver
plugin][https://ocaml.org/docs/metaprogramming#attributes-and-derivers] is
provided to automatically convert OCaml values to and from JSON.

### Installation

The PPX is included in the `melange-json` package. To use it, just add the
`dune` configuration to your project:

```dune
(library
(modes melange)
(preprocess (pps melange-json.ppx)))
```

### Usage

To generate JSON converters for a type, add the `[@@deriving json]` attribute to
a type declaration:

```ocaml
type t = {
a: int;
b: string;
} [@@deriving json]
```

This will generate the following pair of functions:

```ocaml
val of_json : Js.Json.t -> t
val to_json : t -> Js.Json.t
```

#### Generating JSON converters from type expressions

You can also generate JSON converters for a type expression using the `to_json`
and `of_json` extension points:

```ocaml
let json = [%to_json: int * string] (42, "foo")
```

#### Enumeration-like variants

Note that variants where all constructors have no arguments are treated as
enumeration-like variants:

```ocaml
type t = A | B [@@deriving json]
```

Such variants are represented as strings in JSON:

```ocaml
let json = to_json A
(* json = `String "A" *)
```

#### `[@json.default E]`: default values for records

You can specify default values for record fields using the `[@json.default E]`
attribute:

```ocaml
type t = {
a: int;
b: string [@json.default "-"];
} [@@deriving of_json]
let t = of_json (`Assoc ["a", `Int 42])
(* t = { a = 42; b = "-"; } *)
```

#### `[@json.option]`: a shortcut for `[@json.default None]`

When a field has type `_ option` then you can use the `[@json.option]` attribute
to specify that the default value is `None`:

```ocaml
type t = {
a: int;
b: string option [@json.option];
} [@@deriving of_json]
let t = of_json (`Assoc ["a", `Int 42])
(* t = { a = 42; b = None; } *)
```

#### `[@json.key "S"]`: customizing keys for record fields

You can specify custom keys for record fields using the `[@json.key E]`
attribute:

```ocaml
type t = {
a: int [@json.key "A"];
b: string [@json.key "B"];
} [@@deriving of_json]
let t = of_json (`Assoc ["A", `Int 42; "B", `String "foo"])
(* t = { a = 42; b = "foo"; } *)
```

#### `[@json.as "S"]`: customizing the representation of a variant case

You can specify custom representation for a variant case using the `[@json.as
E]` attribute:

```ocaml
type t = A | B [@json.as "bbb"] [@@deriving json]
let json = to_json B
(* json = `String "bbb" *)
```

## License

This work is dual-licensed under LGPL 3.0 and MPL 2.0.
Expand Down
14 changes: 9 additions & 5 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

(generate_opam_files true)

(authors "glennsl")
(authors "glennsl" "Andrey Popp")

(maintainers
"Antonio Nuno Monteiro <[email protected]>"
"Javier Ch\195\161varri <[email protected]>")
"Javier Chávarri <[email protected]>")

(license "LGPL-3.0-only" "MPL-2.0")

Expand All @@ -23,9 +23,10 @@

(package
(name melange-json)
(synopsis "Compositional JSON encode/decode library for Melange")
(synopsis
"Compositional JSON encode/decode library and PPX for Melange, with native compatibility")
(description
"Provides encoders and decoders to convert JSON values into typed values. With the possibility to create custom encoders and decoders.")
"Provides encoders and decoders to convert JSON values into typed values. With the possibility to create custom encoders and decoders and automate them with a PPX.")
(depends
ocaml
(melange
Expand All @@ -35,5 +36,8 @@
(and
(>= "3.10.0")
:with-test))
ppxlib
yojson ; only used for the native version
(opam-check-npm-deps :with-test) ; todo: use with-dev-setup once opam 2.2 is out
(ocaml-lsp-server :with-test)))
(ocaml-lsp-server :with-test)
(ocamlformat :with-test)))
79 changes: 13 additions & 66 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c615cb1

Please sign in to comment.