├── .gitignore
├── ChangeLog.md
├── LICENSE
├── README.md
├── Setup.hs
├── app
└── Main.hs
├── example
├── README.md
├── frontend
│ ├── .gitignore
│ ├── README.md
│ ├── __tests__
│ │ └── Exported
│ │ │ └── SharedTypes_spec.ml
│ ├── bsconfig.json
│ ├── build
│ │ ├── Index.js
│ │ └── index.html
│ ├── package.json
│ ├── src
│ │ ├── Exported
│ │ │ ├── SharedTypes.bs.js
│ │ │ ├── SharedTypes.ml
│ │ │ └── SharedTypes.mli
│ │ ├── Index.bs.js
│ │ ├── Index.re
│ │ ├── ServerFetch.bs.js
│ │ ├── ServerFetch.re
│ │ ├── ServerFetchConfig.bs.js
│ │ ├── ServerFetchConfig.re
│ │ ├── UserSelector.bs.js
│ │ ├── UserSelector.re
│ │ └── index.html
│ ├── webpack.config.js
│ └── yarn.lock
├── server
│ ├── .gitignore
│ ├── ChangeLog.md
│ ├── LICENSE
│ ├── README.md
│ ├── Setup.hs
│ ├── app
│ │ └── Main.hs
│ ├── package.yaml
│ ├── src
│ │ └── Server.hs
│ ├── stack.yaml
│ ├── static
│ │ ├── Index.js
│ │ └── index.html
│ └── test
│ │ └── Spec.hs
├── shared-types-re
│ ├── .gitignore
│ ├── ChangeLog.md
│ ├── LICENSE
│ ├── README.md
│ ├── Setup.hs
│ ├── app
│ │ └── Main.hs
│ ├── handwritten
│ │ ├── Entity.ml
│ │ └── Entity.mli
│ ├── package.yaml
│ ├── src
│ │ └── Shared
│ │ │ └── Types
│ │ │ └── Reason
│ │ │ ├── Package.hs
│ │ │ └── Types.hs
│ ├── stack.yaml
│ └── test
│ │ ├── Spec.hs
│ │ └── golden
│ │ ├── Entity
│ │ └── Entity.json
│ │ ├── Key
│ │ └── Key.json
│ │ ├── Todo
│ │ └── Todo.json
│ │ ├── TodoId
│ │ └── TodoId.json
│ │ ├── User
│ │ └── User.json
│ │ ├── UserId
│ │ └── UserId.json
│ │ └── Username
│ │ └── Username.json
└── shared-types
│ ├── .gitignore
│ ├── ChangeLog.md
│ ├── LICENSE
│ ├── README.md
│ ├── Setup.hs
│ ├── app
│ └── Main.hs
│ ├── package.yaml
│ ├── src
│ └── Shared
│ │ └── Types.hs
│ ├── stack.yaml
│ └── test
│ └── Spec.hs
├── jenkins.sh
├── package.yaml
├── scratch.txt
├── src
└── OCaml
│ ├── BuckleScript
│ ├── Decode.hs
│ ├── Encode.hs
│ ├── Internal
│ │ ├── Module.hs
│ │ ├── Package.hs
│ │ └── Spec.hs
│ ├── Record.hs
│ ├── Spec.hs
│ └── Types.hs
│ ├── Export.hs
│ └── Internal
│ └── Common.hs
├── stack.yaml
├── test.sh
└── test
├── Dependency.hs
├── File.hs
├── FileApp.hs
├── Options.hs
├── Product.hs
├── ProductApp.hs
├── Spec.hs
├── Sum.hs
├── SumApp.hs
├── Util.hs
├── interface
└── golden
│ ├── __tests__
│ ├── file-servant
│ │ └── File_spec.ml
│ ├── file
│ │ └── File_spec.ml
│ ├── product-servant
│ │ ├── Card_spec.ml
│ │ ├── Company_spec.ml
│ │ ├── ComplexProduct_spec.ml
│ │ ├── CustomOption_spec.ml
│ │ ├── OneTypeParameter_spec.ml
│ │ ├── Person_spec.ml
│ │ ├── SimpleChoice_spec.ml
│ │ ├── SubTypeParameter_spec.ml
│ │ ├── ThreeTypeParameters_spec.ml
│ │ ├── TwoTypeParameters_spec.ml
│ │ ├── UnnamedProduct_spec.ml
│ │ └── Wrapper_spec.ml
│ ├── product
│ │ ├── Box_spec.ml
│ │ ├── Card_spec.ml
│ │ ├── Company_spec.ml
│ │ ├── ComplexProduct_spec.ml
│ │ ├── CustomOption_spec.ml
│ │ ├── Key_spec.ml
│ │ ├── OneTypeParameter_spec.ml
│ │ ├── Person_spec.ml
│ │ ├── SimpleChoice_spec.ml
│ │ ├── SubTypeParameter_spec.ml
│ │ ├── ThreeTypeParameters_spec.ml
│ │ ├── TwoTypeParameters_spec.ml
│ │ ├── UnnamedProduct_spec.ml
│ │ └── Wrapper_spec.ml
│ ├── sum-servant
│ │ ├── NameOrIdNumber_spec.ml
│ │ ├── NewType_spec.ml
│ │ ├── OnOrOff_spec.ml
│ │ ├── Result_spec.ml
│ │ ├── SingleSum_spec.ml
│ │ ├── SumVariant_spec.ml
│ │ ├── SumWithRecord_spec.ml
│ │ └── WithTuple_spec.ml
│ └── sum
│ │ ├── NameOrIdNumber_spec.ml
│ │ ├── NewType_spec.ml
│ │ ├── OnOrOff_spec.ml
│ │ ├── Result_spec.ml
│ │ ├── SingleSum_spec.ml
│ │ ├── SumVariant_spec.ml
│ │ ├── SumWithRecord_spec.ml
│ │ └── WithTuple_spec.ml
│ ├── bsconfig.json
│ ├── file
│ ├── File.ml
│ └── File.mli
│ ├── golden
│ ├── dependency
│ │ └── Class
│ │ │ └── Class.json
│ ├── file
│ │ ├── AutoDependingOnManual
│ │ │ └── AutoDependingOnManual.json
│ │ ├── Automobile
│ │ │ └── Automobile.json
│ │ ├── Business
│ │ │ └── Business.json
│ │ ├── NonGenericType
│ │ │ └── NonGenericType.json
│ │ ├── Person
│ │ │ └── Person.json
│ │ └── Wrapper
│ │ │ └── Wrapper.json
│ ├── product
│ │ ├── AuditAction
│ │ │ ├── Create.json
│ │ │ ├── Delete.json
│ │ │ └── Update.json
│ │ ├── AuditModel
│ │ │ └── AuditModel.json
│ │ ├── Card
│ │ │ └── Card.json
│ │ ├── Company
│ │ │ └── Company.json
│ │ ├── Company2
│ │ │ └── Company2.json
│ │ ├── ComplexProduct
│ │ │ └── ComplexProduct.json
│ │ ├── ComplexWrapped
│ │ │ └── ComplexWrapped.json
│ │ ├── EitherWrapped
│ │ │ └── EitherWrapped.json
│ │ ├── HalfWrapped
│ │ │ └── HalfWrapped.json
│ │ ├── InnerBox
│ │ │ └── InnerBox.json
│ │ ├── IntWrapped
│ │ │ └── IntWrapped.json
│ │ ├── MaybeWrapped
│ │ │ └── MaybeWrapped.json
│ │ ├── OneTypeParameter
│ │ │ └── OneTypeParameter.json
│ │ ├── OuterBox
│ │ │ └── OuterBox.json
│ │ ├── PartiallyWrapped
│ │ │ └── PartiallyWrapped.json
│ │ ├── Person
│ │ │ └── Person.json
│ │ ├── ScrambledTypeParameterRefs
│ │ │ └── ScrambledTypeParameterRefs.json
│ │ ├── SecondLayer
│ │ │ └── SecondLayer.json
│ │ ├── SecondLayerFilled
│ │ │ └── SecondLayerFilled.json
│ │ ├── Simple
│ │ │ └── Simple.json
│ │ ├── SimpleChoice
│ │ │ └── SimpleChoice.json
│ │ ├── SqlKey
│ │ │ └── SqlKey.json
│ │ ├── SubTypeParameter
│ │ │ └── SubTypeParameter.json
│ │ ├── Suit
│ │ │ ├── Clubs.json
│ │ │ ├── Diamonds.json
│ │ │ ├── Hearts.json
│ │ │ └── Spades.json
│ │ ├── SumWrapped
│ │ │ ├── SW1.json
│ │ │ ├── SW2.json
│ │ │ ├── SW3.json
│ │ │ └── SW4.json
│ │ ├── Three
│ │ │ └── Three.json
│ │ ├── TupleWrapped
│ │ │ └── TupleWrapped.json
│ │ ├── TwoTypeParameters
│ │ │ └── TwoTypeParameters.json
│ │ ├── UnnamedProduct
│ │ │ └── UnnamedProduct.json
│ │ ├── User
│ │ │ └── User.json
│ │ ├── UserAudit
│ │ │ └── UserAudit.json
│ │ ├── UserId
│ │ │ └── UserId.json
│ │ ├── WrapThree
│ │ │ └── WrapThree.json
│ │ ├── WrapThreeFilled
│ │ │ └── WrapThreeFilled.json
│ │ ├── WrapThreePartiallyFilled
│ │ │ └── WrapThreePartiallyFilled.json
│ │ ├── WrapThreeUnfilled
│ │ │ └── WrapThreeUnfilled.json
│ │ ├── WrappedWrapper
│ │ │ └── WrappedWrapper.json
│ │ ├── Wrapper
│ │ │ └── Wrapper.json
│ │ └── Wrapper2
│ │ │ └── Wrapper2.json
│ ├── school
│ │ └── School
│ │ │ └── School.json
│ ├── subs
│ │ ├── A
│ │ │ └── A.json
│ │ ├── B
│ │ │ └── B.json
│ │ ├── C
│ │ │ └── C.json
│ │ ├── D
│ │ │ └── D.json
│ │ └── E
│ │ │ └── E.json
│ └── sum
│ │ ├── NameOrIdNumber
│ │ ├── IdNumber.json
│ │ └── Name.json
│ │ ├── NewType
│ │ └── NewType.json
│ │ ├── OnOrOff
│ │ ├── Off.json
│ │ └── On.json
│ │ ├── Result
│ │ ├── Error.json
│ │ └── Success.json
│ │ ├── SingleSum
│ │ └── SingleSum.json
│ │ ├── SumVariant
│ │ ├── HasMixed.json
│ │ ├── HasMultipleInts.json
│ │ ├── HasMultipleTuples.json
│ │ ├── HasNameOrIdNumber.json
│ │ ├── HasNothing.json
│ │ ├── HasSingleInt.json
│ │ └── HasSingleTuple.json
│ │ ├── SumWithRecord
│ │ ├── A1.json
│ │ └── B2.json
│ │ └── WithTuple
│ │ └── WithTuple.json
│ ├── options
│ ├── NameOrIdNumber.ml
│ ├── NameOrIdNumber.mli
│ ├── Person.ml
│ └── Person.mli
│ ├── package.json
│ ├── person.json
│ ├── product
│ ├── Box.ml
│ ├── Box.mli
│ ├── Card.ml
│ ├── Card.mli
│ ├── Company.ml
│ ├── Company.mli
│ ├── ComplexProduct.ml
│ ├── ComplexProduct.mli
│ ├── CustomOption.ml
│ ├── CustomOption.mli
│ ├── Key.ml
│ ├── Key.mli
│ ├── OneTypeParameter.ml
│ ├── OneTypeParameter.mli
│ ├── Person.ml
│ ├── Person.mli
│ ├── SimpleChoice.ml
│ ├── SimpleChoice.mli
│ ├── SubTypeParameter.ml
│ ├── SubTypeParameter.mli
│ ├── ThreeTypeParameters.ml
│ ├── ThreeTypeParameters.mli
│ ├── TwoTypeParameters.ml
│ ├── TwoTypeParameters.mli
│ ├── UnnamedProduct.ml
│ ├── UnnamedProduct.mli
│ ├── Wrapper.ml
│ └── Wrapper.mli
│ ├── sum
│ ├── NameOrIdNumber.ml
│ ├── NameOrIdNumber.mli
│ ├── NewType.ml
│ ├── NewType.mli
│ ├── OnOrOff.ml
│ ├── OnOrOff.mli
│ ├── Result.ml
│ ├── Result.mli
│ ├── SingleSum.ml
│ ├── SingleSum.mli
│ ├── SumVariant.ml
│ ├── SumVariant.mli
│ ├── SumWithRecord.ml
│ ├── SumWithRecord.mli
│ ├── WithTuple.ml
│ └── WithTuple.mli
│ ├── webpack.config.js
│ └── yarn.lock
└── ocaml
├── Business.ml
├── Business.mli
├── NonGenericType.ml
├── NonGenericType.mli
├── Person.ml
├── Person.mli
├── Simple.ml
├── Simple.mli
├── Wrapper.ml
└── Wrapper.mli
/.gitignore:
--------------------------------------------------------------------------------
1 | .stack-work
2 | node_modules
3 | .merlin
4 | lib
5 | \#*#
6 | .#*
7 | *.log
8 | test/nointerface/temp
9 | test/interface/temp
10 | *.cabal
11 | *.faulty.json
12 |
--------------------------------------------------------------------------------
/ChangeLog.md:
--------------------------------------------------------------------------------
1 | # Revision history for ocaml-export
2 |
3 | ## 0.14.0.0 -- 2019-04-22
4 | * Fix single enumerator encoding. Now matches aeson.
5 |
6 | ## 0.13.0.0 -- 2019-03-17
7 | * Expose TypeParameterRef constructors. They are useful in some cases.
8 |
9 | ## 0.12.0.0 -- 2018-12-28
10 | * Fix Decode record case when NamedConstructor is an OCamlRef, not a primitive.
11 |
12 | ## 0.11.0.0 -- 2018-12-22
13 | * Support record, encode, decode for type that has a type parameter filled with a non-primitive type (eg. newtype Z = Z (Maybe X))
14 |
15 | ## 0.10.0.0 -- 2018-12-07
16 |
17 | * Support sum-type constructors with non-primitive types
18 | * Remove dodgy-imports warnings with latests wl.pprint text
19 | * addDependentFile for embedded files
20 |
21 | ## 0.9.0.0 -- 2018-06-03
22 |
23 | * Output BuckleScript code requires at least bs-platform 3.1.0.
24 | * Change output BuckleScript code and test code to use `Belt.Result.t` instead of `Js.Result.t`. `Js.Result.t` has been deprecated since bs-platform 3.1.0.
25 | * Add `OInt32` to `OCaml.BuckleScript.Types.OCamlPrimitive` to convert Haskell `Int32` to BuckleScript `int32`.
26 |
27 | ## 0.8.0.0 -- 2018-05-03
28 |
29 | * Support GHC 8.2.2 and drop support for previous GHC versions. 'base >= 4.10' is a requirement.
30 | * Replace 'typelits-witnesses' dependency with 'singletons'.
31 | * Remove use of Overlappable from 'HasEmbeddedFile'. Use 'Nat' flags instead.
32 |
33 | ## 0.7.0.0 -- 2018-02-14
34 |
35 | * Add 'runGoldenSpec' to automate Haskell side file checks.
36 | * Alter 'SpecOptions servantURL' to 'Maybe String'. If it is nothing then produce specs that use files, if Just then spec that uses servant and files.
37 | * Fix encoding for sum type with enumerator.
38 |
39 | ## 0.6.0.0 -- 2018-01-31
40 |
41 | * Properly convert Haskell types to OCaml types that have type parameters.
42 |
43 | * Fix cases when the order of type parameter declarations differs from the order they appear in right hand side of the type declaration.
44 |
45 | * Add 'template-haskell < 2.12.0.0' restriction. OCamlTypeInFile seems to break at runtime with version 2.12.0.0.
46 |
47 | ## 0.5.0.0 -- 2018-01-16
48 |
49 | * Fix 'OCaml.BuckleScript.Encode.renderRef' for OBool.
50 |
51 | ## 0.4.0.0 -- 2018-01-10
52 |
53 | * Add 'OCamlType' instance for ByteString.
54 |
55 | * Add 'HaskellTypeName' to support servant test server for types without Generic. You must manually provide the type's name as a symbol.
56 |
57 | ## 0.3.0.0 -- 2018-01-04
58 |
59 | * 'OCaml.BuckleScript.Encode.renderRef' now add parentheses when rendering: list, optional, either, pair, tuple3, tuple4, tuple5, tuple6.
60 | * Support 'HasEmbeddedFile' for '(:<|>)'.
61 | * 'HasDecoder' now unwraps all OCamlDatatype.
62 |
63 | ## 0.2.0.0 -- 2017-12-29
64 |
65 | * `HasDecoder` properly supports Haskell types like `data X = X String Int`, product type with multiple unnamed records.
66 |
67 | * Support `genericToOCamlDatatype` when one of the type's dependencies implements instance OCamlType without `genericToOCamlDatatype`.
68 |
69 | ## 0.1.1.0 -- 2017-12-19
70 |
71 | * Remove `OCaml.File`. It was unexported, but was causing import errors because it depended on unincluded data files.
72 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright James M.C. Haver II (c) 2017
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | * Neither the name of James M.C. Haver II nor the names of other
17 | contributors may be used to endorse or promote products derived
18 | from this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ocaml-export
4 |
5 | - Export Haskell types to OCaml BuckleScript.
6 | - Export Haskell aeson serializations to OCaml BuckleScript using bs-aeson.
7 | - Automate integration tests between OCaml BuckleScript and Haskell using bs-aeson-spec, quickcheck-arbitrary-adt, hspec-golden-aeson and servant.
8 |
9 | ## Test
10 |
11 | ```
12 | bash test.sh
13 | ```
14 |
15 | ## Todo
16 |
17 | Complete before stablizing and pushing to version 1.0.0.0.
18 |
19 | - Documentation
20 | - Examples
21 | - readthedocs
22 | - More tests.
23 | - Haskell list as OCaml array.
24 | - Support (Map String ..) (Map Text ..) (Map Int ..), must provide one decoder.
25 | - Support (Map x ..) but two encoders/decoders must be provided.
26 | - Resolve dependency order for output code so you are not required to declare 'OCamlPackage' types in the correct order.
27 | - Suppport list of list, option of option, etc.
28 | - Use GHC.TypeList (TypeError).
29 | - Correct Haskell Int (64-bits) to OCaml int, int32, int64 types.
30 | - Support recursive and mutually interdependent types.
31 |
32 | ## Wishlist
33 |
34 | Nice to have but low priority.
35 |
36 | - OCaml source code parser and AST. Would make it a lot easier to handle manually written types, encoders, decoders.
37 | - Output to js_of_ocaml and regular OCaml.
38 |
39 | ## ocaml-export Internal Tests
40 |
41 | If you want to run it against servant:
42 |
43 | ```bash
44 | stack test --flag ocaml-export:servant-spec
45 | cd test/interface/golden
46 | npm install
47 | npm run test
48 | ```
49 |
--------------------------------------------------------------------------------
/Setup.hs:
--------------------------------------------------------------------------------
1 | import Distribution.Simple
2 | main = defaultMain
3 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # ocaml-export servant server and reason-react frontend example
2 |
3 | ## Structure
4 |
5 | - shared-types: data types and servant api
6 | - shared-types-re: an executable that generates the Reason types
7 | from shared-types using ocaml-export
8 | - frontend: a simple Reason React app that uses the automatically
9 | generated types to query the server
10 | - server: a servant server with a mock database, uses shared-types
11 | and serves the fronted
12 |
13 | ## run
14 |
15 | The compile process is not automated yet. You have to do it manually for the time being.
16 | Any time you change the types you need update fronted and the server. Anytime you change
17 | the frontend you need to compile it and re-copy the output to the server's static directory.
18 |
19 | ```
20 | cd shared-types-re
21 | stack build
22 | stack exec generate-reason
23 | cd ../frontend
24 | yarn
25 | yarn build
26 | cd ../server
27 | rm -rf static
28 | cp -rf ../frontend/build static
29 | stack build
30 | stack exec server
31 | ```
32 |
33 | Now you can view the app in your browser `localhost:8001/index.html`
34 |
35 | ## Todo
36 |
37 | - automate the build process
38 | - add authentication
39 | - add admin interface
40 | - unhardcode a few things
41 | - add comments to the code
42 |
--------------------------------------------------------------------------------
/example/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .merlin
3 | .bsb.lock
4 | npm-debug.log
5 | /lib/bs/
6 | /node_modules/
--------------------------------------------------------------------------------
/example/frontend/README.md:
--------------------------------------------------------------------------------
1 | # frontend
2 |
3 | ## Run Project
4 |
5 | ```sh
6 | npm install
7 | npm start
8 | # in another tab
9 | npm run webpack
10 | ```
11 |
12 | After you see the webpack compilation succeed (the `npm run webpack` step), open up `build/index.html` (**no server needed!**). Then modify whichever `.re` file in `src` and refresh the page to see the changes.
13 |
14 | **For more elaborate ReasonReact examples**, please see https://github.com/reasonml-community/reason-react-example
15 |
16 | ## Run Project with Server
17 |
18 | To run with the webpack development server run `npm run server` and view in the browser at http://localhost:8000. Running in this environment provides hot reloading and support for routing; just edit and save the file and the browser will automatically refresh.
19 |
20 | Note that any hot reload on a route will fall back to the root (`/`), so `ReasonReact.Router.dangerouslyGetInitialUrl` will likely be needed alongside the `ReasonReact.Router.watchUrl` logic to handle routing correctly on hot reload refreshes or simply opening the app at a URL that is not the root.
21 |
22 | To use a port other than 8000 set the `PORT` environment variable (`PORT=8080 npm run server`).
23 |
24 | ## Build for Production
25 |
26 | ```sh
27 | npm run build
28 | npm run webpack:production
29 | ```
30 |
31 | This will replace the development artifact `build/Index.js` for an optimized version as well as copy `src/index.html` into `build/`. You can then deploy the contents of the `build` directory (`index.html` and `Index.js`).
32 |
33 | If you make use of routing (via `ReasonReact.Router` or similar logic) ensure that server-side routing handles your routes or that 404's are directed back to `index.html` (which is how the dev server is set up).
34 |
35 | **To enable dead code elimination**, change `bsconfig.json`'s `package-specs` `module` from `"commonjs"` to `"es6"`. Then re-run the above 2 commands. This will allow Webpack to remove unused code.
36 |
--------------------------------------------------------------------------------
/example/frontend/__tests__/Exported/SharedTypes_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | (SharedTypes.decodeEntity AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
4 | (SharedTypes.encodeEntity Aeson.Encode.int Aeson.Encode.int)
5 | "entity"
6 | "test/golden/Entity";
7 |
8 | AesonSpec.goldenDirSpec
9 | SharedTypes.decodeKey
10 | SharedTypes.encodeKey
11 | "key"
12 | "test/golden/Key";
13 |
14 | AesonSpec.goldenDirSpec
15 | SharedTypes.decodeTodoId
16 | SharedTypes.encodeTodoId
17 | "todoId"
18 | "test/golden/TodoId";
19 |
20 | AesonSpec.goldenDirSpec
21 | SharedTypes.decodeUserId
22 | SharedTypes.encodeUserId
23 | "userId"
24 | "test/golden/UserId";
25 |
26 | AesonSpec.goldenDirSpec
27 | SharedTypes.decodeUsername
28 | SharedTypes.encodeUsername
29 | "username"
30 | "test/golden/Username";
31 |
32 | AesonSpec.goldenDirSpec
33 | SharedTypes.decodeTodo
34 | SharedTypes.encodeTodo
35 | "todo"
36 | "test/golden/Todo";
37 |
38 | AesonSpec.goldenDirSpec
39 | SharedTypes.decodeUser
40 | SharedTypes.encodeUser
41 | "user"
42 | "test/golden/User";
43 |
--------------------------------------------------------------------------------
/example/frontend/bsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "reason": {
4 | "react-jsx": 2
5 | },
6 | "sources": {
7 | "dir": "src",
8 | "subdirs": true
9 | },
10 | "package-specs": [
11 | {
12 | "module": "commonjs",
13 | "in-source": true
14 | }
15 | ],
16 | "namespace": true,
17 | "bs-dependencies": ["bs-aeson", "bs-fetch", "reason-react"],
18 | "suffix": ".bs.js",
19 | "bs-dev-dependencies": ["bs-aeson-spec"],
20 | "refmt": 3
21 | }
22 |
--------------------------------------------------------------------------------
/example/frontend/build/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | OCaml Export - Todo Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/example/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "version": "0.1.0",
4 | "scripts": {
5 | "build": "yarn clean && yarn bsb -make-world && webpack",
6 | "clean": "yarn bsb -clean-world",
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "BuckleScript"
11 | ],
12 | "author": "",
13 | "license": "MIT",
14 | "dependencies": {
15 | "bs-aeson": "^3.1.0",
16 | "bs-fetch": "^0.3.1",
17 | "react": "^16.2.0",
18 | "react-dom": "^16.2.0",
19 | "reason-react": ">=0.4.0"
20 | },
21 | "devDependencies": {
22 | "bs-aeson-spec": "^2.2.0",
23 | "bs-platform": "^4.0.18",
24 | "html-webpack-plugin": "^3.2.0",
25 | "webpack": "^4.0.1",
26 | "webpack-cli": "^3.1.1",
27 | "webpack-dev-server": "^3.1.8"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/example/frontend/src/Exported/SharedTypes.ml:
--------------------------------------------------------------------------------
1 | type ('key, 'value) entity =
2 | { entityKey : 'key
3 | ; entityValue : 'value
4 | }
5 |
6 | let encodeEntity encodeKey encodeValue entity =
7 | Aeson.Encode.object_
8 | [ ( "key", encodeKey entity.entityKey )
9 | ; ( "value", encodeValue entity.entityValue )
10 | ]
11 |
12 | let decodeEntity decodeKey decodeValue json =
13 | match Aeson.Decode.
14 | { entityKey = field "key" (fun a -> unwrapResult (decodeKey a)) json
15 | ; entityValue = field "value" (fun a -> unwrapResult (decodeValue a)) json
16 | }
17 | with
18 | | v -> Belt.Result.Ok v
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeEntity: " ^ message)
20 |
21 |
22 | type key =
23 | | Key of int
24 |
25 | let encodeKey x =
26 | match x with
27 | | Key y0 ->
28 | Aeson.Encode.int y0
29 |
30 | let decodeKey json =
31 | match Aeson.Decode.int json with
32 | | v -> Belt.Result.Ok (Key v)
33 | | exception Aeson.Decode.DecodeError msg -> Belt.Result.Error ("decodeKey: " ^ msg)
34 |
35 | type todoId =
36 | | TodoId of key
37 |
38 | let encodeTodoId x =
39 | match x with
40 | | TodoId y0 ->
41 | encodeKey y0
42 |
43 | let decodeTodoId json =
44 | match (Aeson.Decode.unwrapResult (decodeKey json)) with
45 | | v -> Belt.Result.Ok (TodoId v)
46 | | exception Aeson.Decode.DecodeError msg -> Belt.Result.Error ("decodeTodoId: " ^ msg)
47 |
48 | type userId =
49 | | UserId of key
50 |
51 | let encodeUserId x =
52 | match x with
53 | | UserId y0 ->
54 | encodeKey y0
55 |
56 | let decodeUserId json =
57 | match (Aeson.Decode.unwrapResult (decodeKey json)) with
58 | | v -> Belt.Result.Ok (UserId v)
59 | | exception Aeson.Decode.DecodeError msg -> Belt.Result.Error ("decodeUserId: " ^ msg)
60 |
61 | type username =
62 | | Username of string
63 |
64 | let encodeUsername x =
65 | match x with
66 | | Username y0 ->
67 | Aeson.Encode.string y0
68 |
69 | let decodeUsername json =
70 | match Aeson.Decode.string json with
71 | | v -> Belt.Result.Ok (Username v)
72 | | exception Aeson.Decode.DecodeError msg -> Belt.Result.Error ("decodeUsername: " ^ msg)
73 |
74 | type todo =
75 | { description : string
76 | ; completed : bool
77 | }
78 |
79 | let encodeTodo x =
80 | Aeson.Encode.object_
81 | [ ( "description", Aeson.Encode.string x.description )
82 | ; ( "completed", Aeson.Encode.bool x.completed )
83 | ]
84 |
85 | let decodeTodo json =
86 | match Aeson.Decode.
87 | { description = field "description" string json
88 | ; completed = field "completed" bool json
89 | }
90 | with
91 | | v -> Belt.Result.Ok v
92 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeTodo: " ^ message)
93 |
94 | type user =
95 | { username : username
96 | ; password : string
97 | }
98 |
99 | let encodeUser x =
100 | Aeson.Encode.object_
101 | [ ( "username", encodeUsername x.username )
102 | ; ( "password", Aeson.Encode.string x.password )
103 | ]
104 |
105 | let decodeUser json =
106 | match Aeson.Decode.
107 | { username = field "username" (fun a -> unwrapResult (decodeUsername a)) json
108 | ; password = field "password" string json
109 | }
110 | with
111 | | v -> Belt.Result.Ok v
112 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeUser: " ^ message)
113 |
--------------------------------------------------------------------------------
/example/frontend/src/Exported/SharedTypes.mli:
--------------------------------------------------------------------------------
1 | type ('key, 'value) entity =
2 | { entityKey : 'key
3 | ; entityValue : 'value
4 | }
5 |
6 | val encodeEntity : ('key -> Js_json.t) -> ('value -> Js_json.t) -> ('key, 'value) entity -> Js_json.t
7 |
8 | val decodeEntity : (Js_json.t -> ('key, string) Belt.Result.t) -> (Js_json.t -> ('value, string) Belt.Result.t) -> Js_json.t -> (('key, 'value) entity, string) Belt.Result.t
9 |
10 |
11 | type key =
12 | | Key of int
13 |
14 | val encodeKey : key -> Js_json.t
15 |
16 | val decodeKey : Js_json.t -> (key, string) Belt.Result.t
17 |
18 | type todoId =
19 | | TodoId of key
20 |
21 | val encodeTodoId : todoId -> Js_json.t
22 |
23 | val decodeTodoId : Js_json.t -> (todoId, string) Belt.Result.t
24 |
25 | type userId =
26 | | UserId of key
27 |
28 | val encodeUserId : userId -> Js_json.t
29 |
30 | val decodeUserId : Js_json.t -> (userId, string) Belt.Result.t
31 |
32 | type username =
33 | | Username of string
34 |
35 | val encodeUsername : username -> Js_json.t
36 |
37 | val decodeUsername : Js_json.t -> (username, string) Belt.Result.t
38 |
39 | type todo =
40 | { description : string
41 | ; completed : bool
42 | }
43 |
44 | val encodeTodo : todo -> Js_json.t
45 |
46 | val decodeTodo : Js_json.t -> (todo, string) Belt.Result.t
47 |
48 | type user =
49 | { username : username
50 | ; password : string
51 | }
52 |
53 | val encodeUser : user -> Js_json.t
54 |
55 | val decodeUser : Js_json.t -> (user, string) Belt.Result.t
56 |
--------------------------------------------------------------------------------
/example/frontend/src/Index.bs.js:
--------------------------------------------------------------------------------
1 | // Generated by BUCKLESCRIPT VERSION 4.0.18, PLEASE EDIT WITH CARE
2 | 'use strict';
3 |
4 | var ReactDOMRe = require("reason-react/src/ReactDOMRe.js");
5 | var ReasonReact = require("reason-react/src/ReasonReact.js");
6 | var UserSelector$Frontend = require("./UserSelector.bs.js");
7 |
8 | ReactDOMRe.renderToElementWithId(ReasonReact.element(undefined, undefined, UserSelector$Frontend.make(/* array */[])), "root");
9 |
10 | /* Not a pure module */
11 |
--------------------------------------------------------------------------------
/example/frontend/src/Index.re:
--------------------------------------------------------------------------------
1 | ReactDOMRe.renderToElementWithId(, "root");
--------------------------------------------------------------------------------
/example/frontend/src/ServerFetchConfig.bs.js:
--------------------------------------------------------------------------------
1 | // Generated by BUCKLESCRIPT VERSION 4.0.18, PLEASE EDIT WITH CARE
2 | 'use strict';
3 |
4 |
5 | var getBaseUrl = (
6 | function () {
7 | var cfg = window.__serverFetchConfig;
8 | if (typeof(cfg) !== "undefined") {
9 | return cfg.scheme + "://" + cfg.host + ":" + cfg.port;
10 | } else {
11 | return "";
12 | }
13 | }
14 | );
15 |
16 | var config = /* record */[/* baseUrl */"http://localhost:8001"];
17 |
18 | exports.getBaseUrl = getBaseUrl;
19 | exports.config = config;
20 | /* getBaseUrl Not a pure module */
21 |
--------------------------------------------------------------------------------
/example/frontend/src/ServerFetchConfig.re:
--------------------------------------------------------------------------------
1 | module type Config = {let baseUrl: string;};
2 |
3 | type projectConfig = {baseUrl: string};
4 |
5 | let getBaseUrl: unit => string = [%bs.raw
6 | {|
7 | function () {
8 | var cfg = window.__serverFetchConfig;
9 | if (typeof(cfg) !== "undefined") {
10 | return cfg.scheme + "://" + cfg.host + ":" + cfg.port;
11 | } else {
12 | return "";
13 | }
14 | }
15 | |}
16 | ];
17 |
18 | let config = {baseUrl: "http://localhost:8001"};
--------------------------------------------------------------------------------
/example/frontend/src/UserSelector.re:
--------------------------------------------------------------------------------
1 | open SharedTypes;
2 |
3 | let usernameToString = (username: username) =>
4 | switch (username) {
5 | | Username(s) => s
6 | };
7 |
8 | module Fetch =
9 | ServerFetch.MakeServerFetch({
10 | let baseUrl = ServerFetchConfig.config.baseUrl;
11 | });
12 |
13 | type page =
14 | | UsersPage
15 | | TodosPage;
16 |
17 | type state = {
18 | users: array(entity(userId, user)),
19 | page,
20 | todos: array(entity(todoId, todo)),
21 | };
22 |
23 | let initialState = () => {users: [||], page: UsersPage, todos: [||]};
24 |
25 | /* Action declaration */
26 | type action =
27 | | UpdateUsers(array(entity(userId, user)))
28 | | UpdatePage(page)
29 | | FetchTodos(userId)
30 | | GotTodos(array(entity(todoId, todo)));
31 |
32 | let reducer = (action, state) =>
33 | switch (action) {
34 | | UpdateUsers(users) => ReasonReact.Update({...state, users})
35 | | UpdatePage(page) => ReasonReact.Update({...state, page})
36 | | FetchTodos(userId) =>
37 | ReasonReact.UpdateWithSideEffects(
38 | {...state, page: TodosPage},
39 | (
40 | ({send}) =>
41 | Fetch.getUserTodos(userId)
42 | |> Js.Promise.then_(todos => {
43 | send(GotTodos(todos));
44 | Js.Promise.resolve();
45 | })
46 | |> ignore
47 | ),
48 | )
49 | | GotTodos(todos) => ReasonReact.Update({...state, todos})
50 | };
51 |
52 | let component = ReasonReact.reducerComponent("UserSelector");
53 |
54 | let make = _children => {
55 | ...component,
56 | initialState,
57 | didMount: self =>
58 | Fetch.getUsers()
59 | |> Js.Promise.then_(rUsers => {
60 | self.send(UpdateUsers(rUsers));
61 | Js.Promise.resolve();
62 | })
63 | |> ignore,
64 | reducer,
65 | render: ({send, state}) =>
66 |
67 | (
68 | if (state.page == UsersPage) {
69 | Array.map(
70 | (user: entity(userId, user)) =>
71 |
send(FetchTodos(user.entityKey)))>
72 | (
73 | ReasonReact.string(
74 | usernameToString(user.entityValue.username),
75 | )
76 | )
77 |
,
78 | state.users,
79 | )
80 | |> ReasonReact.array;
81 | } else if (state.page == TodosPage) {
82 |
83 |
84 | (
85 | if (Array.length(state.todos) == 0) {
86 | ReasonReact.string("No todos");
87 | } else {
88 | Array.map(
89 | (todo: entity(todoId, todo)) =>
90 |
91 | (ReasonReact.string(todo.entityValue.description))
92 |
,
93 | state.todos,
94 | )
95 | |> ReasonReact.array;
96 | }
97 | )
98 |
99 |
100 |
103 |
104 |
;
105 | } else {
106 | ReasonReact.null;
107 | }
108 | )
109 |
,
110 | };
--------------------------------------------------------------------------------
/example/frontend/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | OCaml Export - Todo Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/example/frontend/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const outputDir = path.join(__dirname, 'build/');
4 |
5 | const isProd = process.env.NODE_ENV === 'production';
6 |
7 | module.exports = {
8 | entry: './src/Index.bs.js',
9 | mode: isProd ? 'production' : 'development',
10 | output: {
11 | path: outputDir,
12 | filename: 'Index.js'
13 | },
14 | plugins: [
15 | new HtmlWebpackPlugin({
16 | template: 'src/index.html',
17 | inject: false
18 | })
19 | ],
20 | devServer: {
21 | compress: true,
22 | contentBase: outputDir,
23 | port: process.env.PORT || 8000,
24 | historyApiFallback: true
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/example/server/.gitignore:
--------------------------------------------------------------------------------
1 | .stack-work/
2 | server.cabal
3 | *~
--------------------------------------------------------------------------------
/example/server/ChangeLog.md:
--------------------------------------------------------------------------------
1 | # Changelog for server
2 |
3 | ## Unreleased changes
4 |
--------------------------------------------------------------------------------
/example/server/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright Author name here (c) 2019
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | * Neither the name of Author name here nor the names of other
17 | contributors may be used to endorse or promote products derived
18 | from this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/example/server/README.md:
--------------------------------------------------------------------------------
1 | # server
2 |
--------------------------------------------------------------------------------
/example/server/Setup.hs:
--------------------------------------------------------------------------------
1 | import Distribution.Simple
2 | main = defaultMain
3 |
--------------------------------------------------------------------------------
/example/server/app/Main.hs:
--------------------------------------------------------------------------------
1 | module Main where
2 |
3 | import Server
4 |
5 | main :: IO ()
6 | main = runServer
7 |
--------------------------------------------------------------------------------
/example/server/package.yaml:
--------------------------------------------------------------------------------
1 | name: server
2 | version: 0.1.0.0
3 | github: "plow-technologies/ocaml-export"
4 | license: BSD3
5 | author: "James M.C. Haver II"
6 | maintainer: "james.haver@plowtech.net"
7 | copyright: "2019 Plow Technologies"
8 |
9 | extra-source-files:
10 | - README.md
11 | - ChangeLog.md
12 |
13 | description: Please see the README on GitHub at
14 |
15 | dependencies:
16 | - base >= 4.7 && < 5
17 | - aeson
18 | - servant
19 | - servant-server
20 | - shared-types
21 | - stm
22 | - wai
23 | - warp
24 |
25 | library:
26 | source-dirs: src
27 |
28 | executables:
29 | server:
30 | main: Main.hs
31 | source-dirs: app
32 | ghc-options:
33 | - -threaded
34 | - -rtsopts
35 | - -with-rtsopts=-N
36 | dependencies:
37 | - server
38 |
--------------------------------------------------------------------------------
/example/server/stack.yaml:
--------------------------------------------------------------------------------
1 | resolver: lts-13.13
2 |
3 | packages:
4 | - .
5 | - "../shared-types"
6 |
--------------------------------------------------------------------------------
/example/server/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | OCaml Export - Todo Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/example/server/test/Spec.hs:
--------------------------------------------------------------------------------
1 | main :: IO ()
2 | main = putStrLn "Test suite not yet implemented"
3 |
--------------------------------------------------------------------------------
/example/shared-types-re/.gitignore:
--------------------------------------------------------------------------------
1 | .stack-work/
2 | shared-types-re.cabal
3 | *~
--------------------------------------------------------------------------------
/example/shared-types-re/ChangeLog.md:
--------------------------------------------------------------------------------
1 | # Changelog for shared-types-re
2 |
3 | ## Unreleased changes
4 |
--------------------------------------------------------------------------------
/example/shared-types-re/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright Author name here (c) 2019
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | * Neither the name of Author name here nor the names of other
17 | contributors may be used to endorse or promote products derived
18 | from this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/example/shared-types-re/README.md:
--------------------------------------------------------------------------------
1 | # shared-types-re
2 |
--------------------------------------------------------------------------------
/example/shared-types-re/Setup.hs:
--------------------------------------------------------------------------------
1 | import Distribution.Simple
2 | main = defaultMain
3 |
--------------------------------------------------------------------------------
/example/shared-types-re/app/Main.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE FlexibleContexts #-}
2 | module Main where
3 |
4 | import System.Environment (getArgs)
5 | import System.Exit (exitFailure)
6 |
7 | import OCaml.Export
8 | import qualified Shared.Types.Reason.Package as SharedTypes
9 |
10 | main :: IO ()
11 | main = do
12 | mkPackageWithGolden
13 | (Proxy :: Proxy SharedTypes.SharedTypesPackage)
14 | "test/golden"
15 | SharedTypes.fileMap
16 |
17 | where
18 | mkPackageWithGolden proxy dir fileMap = do
19 | mkGoldenFiles proxy 5 dir
20 | mkPackage proxy (PackageOptions "." "../frontend/src/Exported" fileMap True $ Just $ SpecOptions "../frontend/__tests__/Exported" dir Nothing)
21 |
--------------------------------------------------------------------------------
/example/shared-types-re/handwritten/Entity.ml:
--------------------------------------------------------------------------------
1 | type ('key, 'value) entity =
2 | { entityKey : 'key
3 | ; entityValue : 'value
4 | }
5 |
6 | let encodeEntity encodeKey encodeValue entity =
7 | Aeson.Encode.object_
8 | [ ( "key", encodeKey entity.entityKey )
9 | ; ( "value", encodeValue entity.entityValue )
10 | ]
11 |
12 | let decodeEntity decodeKey decodeValue json =
13 | match Aeson.Decode.
14 | { entityKey = field "key" (fun a -> unwrapResult (decodeKey a)) json
15 | ; entityValue = field "value" (fun a -> unwrapResult (decodeValue a)) json
16 | }
17 | with
18 | | v -> Belt.Result.Ok v
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeEntity: " ^ message)
20 |
--------------------------------------------------------------------------------
/example/shared-types-re/handwritten/Entity.mli:
--------------------------------------------------------------------------------
1 | type ('key, 'value) entity =
2 | { entityKey : 'key
3 | ; entityValue : 'value
4 | }
5 |
6 | val encodeEntity : ('key -> Js_json.t) -> ('value -> Js_json.t) -> ('key, 'value) entity -> Js_json.t
7 |
8 | val decodeEntity : (Js_json.t -> ('key, string) Belt.Result.t) -> (Js_json.t -> ('value, string) Belt.Result.t) -> Js_json.t -> (('key, 'value) entity, string) Belt.Result.t
9 |
--------------------------------------------------------------------------------
/example/shared-types-re/package.yaml:
--------------------------------------------------------------------------------
1 | name: shared-types-re
2 | version: 0.1.0.0
3 | github: "plow-technologies/ocaml-export"
4 | license: BSD3
5 | author: "James M.C. Haver II"
6 | maintainer: "james.haver@plowtech.net"
7 | copyright: "2019 Plow Technologies"
8 |
9 | extra-source-files:
10 | - README.md
11 | - ChangeLog.md
12 |
13 | description: Please see the README on GitHub at
14 |
15 | dependencies:
16 | - base >= 4.7 && < 5
17 | - containers
18 | - ocaml-export
19 | - QuickCheck
20 | - quickcheck-arbitrary-adt
21 | - shared-types
22 | - text
23 | - time
24 |
25 | library:
26 | source-dirs: src
27 |
28 | executables:
29 | generate-reason:
30 | main: Main.hs
31 | source-dirs: app
32 | ghc-options:
33 | - -threaded
34 | - -rtsopts
35 | - -with-rtsopts=-N
36 | dependencies:
37 | - shared-types-re
38 |
39 | tests:
40 | shared-types-re-test:
41 | main: Spec.hs
42 | source-dirs: test
43 | ghc-options:
44 | - -threaded
45 | - -rtsopts
46 | - -with-rtsopts=-N
47 | dependencies:
48 | - hspec
49 | - shared-types-re
50 |
--------------------------------------------------------------------------------
/example/shared-types-re/src/Shared/Types/Reason/Package.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE TemplateHaskell #-}
2 |
3 | module Shared.Types.Reason.Package
4 | ( fileMap
5 | , SharedTypesPackage
6 | ) where
7 |
8 | import qualified Data.Map as Map
9 | import Data.Proxy
10 | import OCaml.Export
11 | import Shared.Types.Reason.Types
12 |
13 | fileMap :: Map.Map String EmbeddedOCamlFiles
14 | fileMap = Map.fromList $(mkFiles True False (Proxy :: Proxy SharedTypesPackage))
15 |
--------------------------------------------------------------------------------
/example/shared-types-re/src/Shared/Types/Reason/Types.hs:
--------------------------------------------------------------------------------
1 | {-# OPTIONS_GHC -fno-warn-orphans #-}
2 |
3 | {-# LANGUAGE DataKinds #-}
4 | {-# LANGUAGE DeriveGeneric #-}
5 | {-# LANGUAGE FlexibleInstances #-}
6 | {-# LANGUAGE OverloadedStrings #-}
7 | {-# LANGUAGE RecordWildCards #-}
8 | {-# LANGUAGE ScopedTypeVariables #-}
9 | {-# LANGUAGE StandaloneDeriving #-}
10 | {-# LANGUAGE TypeOperators #-}
11 |
12 | module Shared.Types.Reason.Types where
13 |
14 | import Data.Time.Clock.POSIX
15 | import Data.Time
16 | import qualified Data.Text as T
17 | import OCaml.Export
18 | import Test.QuickCheck
19 | import Test.QuickCheck.Arbitrary.ADT
20 |
21 | import Shared.Types
22 | (Entity(..), IsKey(..), Key(..), Todo(..), TodoId(..), User(..), UserId(..), Username(..))
23 |
24 | -- because of the restriction we put on Entity
25 | -- we have to make this dummy instance
26 | instance IsKey TypeParameterRef0 where
27 | fromKey (Key k) = TypeParameterRef0 (fromIntegral k)
28 | toKey (TypeParameterRef0 k) = Key (fromIntegral k)
29 |
30 | type SharedTypesPackage =
31 | OCamlPackage "shared-types" '[] :>
32 | (OCamlModule '["SharedTypes"]
33 | :> OCamlTypeInFile (Entity TypeParameterRef0 TypeParameterRef1) "handwritten/Entity"
34 | :> Key
35 | :> TodoId
36 | :> UserId
37 | :> Username
38 | :> Todo
39 | :> User
40 | )
41 |
42 | instance (IsKey a, Arbitrary a, Arbitrary b) => Arbitrary (Entity a b) where
43 | arbitrary = Entity <$> arbitrary <*> arbitrary
44 |
45 | instance (IsKey a, Arbitrary a, ToADTArbitrary a, Arbitrary b, ToADTArbitrary b) => ToADTArbitrary (Entity a b) where
46 | toADTArbitrarySingleton Proxy =
47 | ADTArbitrarySingleton "Shared.Types" "Entity"
48 | <$> oneof
49 | [ ConstructorArbitraryPair "Entity" <$> (Entity <$> arbitrary <*> arbitrary)
50 | ]
51 |
52 | toADTArbitrary Proxy =
53 | ADTArbitrary "Shared.Types" "Entity"
54 | <$> sequence
55 | [ ConstructorArbitraryPair "Entity" <$> (Entity <$> arbitrary <*> arbitrary) ]
56 |
57 | instance OCamlType (Entity TypeParameterRef0 TypeParameterRef1) where
58 | toOCamlType _ = typeableToOCamlType (Proxy :: Proxy (Entity TypeParameterRef0 TypeParameterRef1))
59 |
60 | instance Arbitrary Key where
61 | arbitrary = Key <$> arbitrary
62 | instance ToADTArbitrary Key
63 | instance OCamlType Key
64 |
65 | instance Arbitrary TodoId where
66 | arbitrary = TodoId <$> arbitrary
67 | instance ToADTArbitrary TodoId
68 | instance OCamlType TodoId
69 |
70 | instance Arbitrary Todo where
71 | arbitrary = Todo <$> arbitrary <*> arbitrary -- <*> arbitrary <*> arbitrary
72 | instance ToADTArbitrary Todo
73 | instance OCamlType Todo
74 |
75 | instance Arbitrary UserId where
76 | arbitrary = UserId <$> arbitrary
77 | instance ToADTArbitrary UserId
78 | instance OCamlType UserId
79 |
80 | instance Arbitrary User where
81 | arbitrary = User <$> arbitrary <*> arbitrary
82 | instance ToADTArbitrary User
83 | instance OCamlType User
84 |
85 | instance Arbitrary Username where
86 | arbitrary = Username <$> arbitrary
87 | instance ToADTArbitrary Username
88 | instance OCamlType Username
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | instance Arbitrary T.Text where
98 | arbitrary = T.pack <$> arbitrary
99 |
100 | instance Arbitrary UTCTime where
101 | arbitrary = posixSecondsToUTCTime . fromIntegral <$> (arbitrary :: Gen Integer)
102 |
--------------------------------------------------------------------------------
/example/shared-types-re/stack.yaml:
--------------------------------------------------------------------------------
1 | resolver: lts-13.13
2 |
3 | packages:
4 | - .
5 | - "../shared-types"
6 | - "../.."
7 |
--------------------------------------------------------------------------------
/example/shared-types-re/test/Spec.hs:
--------------------------------------------------------------------------------
1 | import OCaml.Export
2 | import Shared.Types.Reason.Types
3 | import Test.Hspec
4 |
5 | main :: IO ()
6 | main = do
7 | mkGoldenFiles (Proxy :: Proxy SharedTypesPackage) 100 "test/golden"
8 |
9 | hspec $ runGoldenSpec (Proxy :: Proxy SharedTypesPackage) 100 "test/golden"
10 |
--------------------------------------------------------------------------------
/example/shared-types-re/test/golden/Key/Key.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -9016493426044224665,
3 | "samples": [
4 | 14712555,
5 | 7437287,
6 | 14792562,
7 | 1480808,
8 | 4190332,
9 | 13155843,
10 | 11439407,
11 | 1775515,
12 | 7532512,
13 | 4661264,
14 | 7024275,
15 | 6668764,
16 | 7985246,
17 | 13438602,
18 | 12485020,
19 | 4081590,
20 | 5961914,
21 | 15251722,
22 | 6795836,
23 | 13222274,
24 | 1604816,
25 | 6338079,
26 | 274059,
27 | 28615,
28 | 4034922,
29 | 4777494,
30 | 12594374,
31 | 4974051,
32 | 11277270,
33 | 2261227,
34 | 9305863,
35 | 11828696,
36 | 11907381,
37 | 14136564,
38 | 14820928,
39 | 4382107,
40 | 2445010,
41 | 15375736,
42 | 16715365,
43 | 11113750,
44 | 7078096,
45 | 13092708,
46 | 3668060,
47 | 12258593,
48 | 10753589,
49 | 10467312,
50 | 3331722,
51 | 16658658,
52 | 9953561,
53 | 532131,
54 | 3123232,
55 | 10916078,
56 | 12981692,
57 | 5916980,
58 | 11030128,
59 | 7675371,
60 | 9797685,
61 | 9493925,
62 | 3443565,
63 | 5107255,
64 | 5941828,
65 | 11209041,
66 | 11960801,
67 | 14212318,
68 | 10422842,
69 | 10273439,
70 | 1964415,
71 | 781712,
72 | 6323020,
73 | 12073073,
74 | 9750335,
75 | 7870988,
76 | 13512407,
77 | 4524596,
78 | 4416529,
79 | 14022590,
80 | 16490956,
81 | 574126,
82 | 13123093,
83 | 15785711,
84 | 16199621,
85 | 866033,
86 | 4772027,
87 | 6862673,
88 | 13671382,
89 | 3457404,
90 | 4787414,
91 | 12328771,
92 | 9548103,
93 | 5053808,
94 | 11707982,
95 | 1703195,
96 | 2671780,
97 | 4675495,
98 | 14811032,
99 | 3403113,
100 | 3622502,
101 | 2364409,
102 | 15671864,
103 | 2360132
104 | ]
105 | }
--------------------------------------------------------------------------------
/example/shared-types-re/test/golden/TodoId/TodoId.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -5370017512571779706,
3 | "samples": [
4 | 12714750,
5 | 48180,
6 | 15216059,
7 | 13032757,
8 | 4502333,
9 | 14824121,
10 | 12775197,
11 | 10972032,
12 | 15028092,
13 | 15015365,
14 | 3559901,
15 | 615304,
16 | 3513444,
17 | 8975503,
18 | 13614715,
19 | 3377585,
20 | 8636632,
21 | 460582,
22 | 12273922,
23 | 6474639,
24 | 5792685,
25 | 2999549,
26 | 5523174,
27 | 14619030,
28 | 892818,
29 | 7436672,
30 | 6130050,
31 | 16246841,
32 | 14883374,
33 | 9503905,
34 | 14508021,
35 | 12603684,
36 | 1322568,
37 | 3342408,
38 | 12576237,
39 | 16043243,
40 | 13066615,
41 | 14210384,
42 | 5871673,
43 | 5867524,
44 | 8968753,
45 | 4671933,
46 | 3228015,
47 | 4805271,
48 | 12085015,
49 | 13750083,
50 | 13753302,
51 | 11725104,
52 | 16030444,
53 | 1511088,
54 | 16284032,
55 | 4080328,
56 | 16525945,
57 | 5502429,
58 | 10439009,
59 | 7034842,
60 | 14461692,
61 | 11047743,
62 | 522861,
63 | 11379924,
64 | 11781851,
65 | 9389506,
66 | 4553996,
67 | 11533374,
68 | 766157,
69 | 12381207,
70 | 8338576,
71 | 13337164,
72 | 4057039,
73 | 3111867,
74 | 12991803,
75 | 15190716,
76 | 7845301,
77 | 10668892,
78 | 10594743,
79 | 6189965,
80 | 3289733,
81 | 16601887,
82 | 4844259,
83 | 2525729,
84 | 6307988,
85 | 7894810,
86 | 9614952,
87 | 6258536,
88 | 4840102,
89 | 15368432,
90 | 6905675,
91 | 10706986,
92 | 6125804,
93 | 3042528,
94 | 1242615,
95 | 5733302,
96 | 554569,
97 | 13892110,
98 | 16367184,
99 | 9329612,
100 | 7461491,
101 | 959756,
102 | 13445600,
103 | 7427605
104 | ]
105 | }
--------------------------------------------------------------------------------
/example/shared-types-re/test/golden/UserId/UserId.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -5093999010263708143,
3 | "samples": [
4 | 3028242,
5 | 8999914,
6 | 15168533,
7 | 127708,
8 | 4381148,
9 | 3992934,
10 | 3258504,
11 | 6916557,
12 | 8800571,
13 | 8897664,
14 | 10375706,
15 | 13248134,
16 | 7455144,
17 | 3093037,
18 | 8326406,
19 | 14919782,
20 | 10732389,
21 | 7435949,
22 | 6844595,
23 | 10279866,
24 | 3457624,
25 | 15933670,
26 | 824013,
27 | 4642393,
28 | 2512434,
29 | 284855,
30 | 1386282,
31 | 8632007,
32 | 10133744,
33 | 4180439,
34 | 6365843,
35 | 7910376,
36 | 11388970,
37 | 8406803,
38 | 12343093,
39 | 11847212,
40 | 15321735,
41 | 4747706,
42 | 5889729,
43 | 6331352,
44 | 15663849,
45 | 13772356,
46 | 16172884,
47 | 12459110,
48 | 7143349,
49 | 9570796,
50 | 16775226,
51 | 6428390,
52 | 422648,
53 | 2168914,
54 | 14352328,
55 | 7134985,
56 | 14099254,
57 | 7333550,
58 | 8081575,
59 | 746151,
60 | 8360810,
61 | 6930455,
62 | 10665611,
63 | 7264848,
64 | 4935709,
65 | 8494254,
66 | 6022911,
67 | 15927909,
68 | 645697,
69 | 104158,
70 | 14313882,
71 | 11137850,
72 | 4272423,
73 | 16712363,
74 | 11333087,
75 | 2876488,
76 | 16099456,
77 | 11346059,
78 | 3014458,
79 | 131611,
80 | 566311,
81 | 12582047,
82 | 7979208,
83 | 8324229,
84 | 40792,
85 | 10484055,
86 | 8645376,
87 | 9236610,
88 | 11890050,
89 | 9961247,
90 | 578042,
91 | 2867722,
92 | 13554669,
93 | 6211901,
94 | 16519162,
95 | 16761875,
96 | 805322,
97 | 15875302,
98 | 563868,
99 | 3207819,
100 | 11756087,
101 | 6766121,
102 | 8462496,
103 | 13583838
104 | ]
105 | }
--------------------------------------------------------------------------------
/example/shared-types/.gitignore:
--------------------------------------------------------------------------------
1 | .stack-work/
2 | shared-types.cabal
3 | *~
--------------------------------------------------------------------------------
/example/shared-types/ChangeLog.md:
--------------------------------------------------------------------------------
1 | # Changelog for shared-types
2 |
3 | ## Unreleased changes
4 |
--------------------------------------------------------------------------------
/example/shared-types/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright Author name here (c) 2019
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | * Neither the name of Author name here nor the names of other
17 | contributors may be used to endorse or promote products derived
18 | from this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/example/shared-types/README.md:
--------------------------------------------------------------------------------
1 | # shared-types
2 |
--------------------------------------------------------------------------------
/example/shared-types/Setup.hs:
--------------------------------------------------------------------------------
1 | import Distribution.Simple
2 | main = defaultMain
3 |
--------------------------------------------------------------------------------
/example/shared-types/app/Main.hs:
--------------------------------------------------------------------------------
1 | module Main where
2 |
3 | import Lib
4 |
5 | main :: IO ()
6 | main = someFunc
7 |
--------------------------------------------------------------------------------
/example/shared-types/package.yaml:
--------------------------------------------------------------------------------
1 | name: shared-types
2 | version: 0.1.0.0
3 | github: "plow-technologies/ocaml-export"
4 | license: BSD3
5 | author: "James M.C. Haver II"
6 | maintainer: "james.haver@plowtech.net"
7 | copyright: "2019 Plow Technologies"
8 |
9 | extra-source-files:
10 | - README.md
11 | - ChangeLog.md
12 |
13 | description: Please see the README on GitHub at
14 |
15 | dependencies:
16 | - base >= 4.7 && < 5
17 | - aeson
18 | - http-api-data
19 | - servant
20 | - text
21 | - time
22 |
23 | library:
24 | source-dirs: src
25 |
26 | tests:
27 | shared-types-test:
28 | main: Spec.hs
29 | source-dirs: test
30 | ghc-options:
31 | - -threaded
32 | - -rtsopts
33 | - -with-rtsopts=-N
34 | dependencies:
35 | - shared-types
36 |
--------------------------------------------------------------------------------
/example/shared-types/stack.yaml:
--------------------------------------------------------------------------------
1 | resolver: lts-13.13
2 |
3 | packages:
4 | - .
5 |
--------------------------------------------------------------------------------
/example/shared-types/test/Spec.hs:
--------------------------------------------------------------------------------
1 | main :: IO ()
2 | main = putStrLn "Test suite not yet implemented"
3 |
--------------------------------------------------------------------------------
/package.yaml:
--------------------------------------------------------------------------------
1 | name: ocaml-export
2 | version: 0.14.0
3 | synopsis: Convert Haskell types in OCaml types
4 | description: Use GHC.Generics and Typeable to convert Haskell types to OCaml types. Convert aeson serialization to ocaml.
5 | category: Web
6 | author: James M.C. Haver II
7 | maintainer: james.haver@plowtech.net
8 | copyright: 2017 Plow Technologies
9 | license: BSD3
10 | github: plow-technologies/ocaml-export
11 |
12 | dependencies:
13 | - base >= 4.10 && < 5
14 | - aeson
15 | - bytestring
16 | - containers
17 | - directory
18 | - filepath
19 | - hspec
20 | - hspec-golden-aeson >= 0.4.0.0
21 | - QuickCheck
22 | - quickcheck-arbitrary-adt
23 | - servant
24 | - servant-server
25 | - singletons
26 | - text
27 | - template-haskell
28 | - time
29 | ghc-options:
30 | - -Wall
31 | - -Werror
32 | - -Wcompat
33 | - -Wincomplete-record-updates
34 | - -Wincomplete-uni-patterns
35 | - -Wredundant-constraints
36 |
37 | library:
38 | source-dirs: src
39 | exposed-modules:
40 | - OCaml.Export
41 | - OCaml.BuckleScript.Decode
42 | - OCaml.BuckleScript.Encode
43 | - OCaml.BuckleScript.Record
44 | - OCaml.BuckleScript.Spec
45 | - OCaml.BuckleScript.Types
46 | # Internal packages
47 | - OCaml.Internal.Common
48 | - OCaml.BuckleScript.Internal.Spec
49 | - OCaml.BuckleScript.Internal.Module
50 | - OCaml.BuckleScript.Internal.Package
51 | dependencies:
52 | - file-embed
53 | - formatting
54 | - mtl
55 | - split
56 | - wl-pprint-text
57 | ghc-options:
58 | - -Wredundant-constraints
59 | - -fprint-potential-instances
60 |
61 | tests:
62 | spec:
63 | main: Spec.hs
64 | source-dirs: test
65 | dependencies:
66 | - ocaml-export
67 | - process
68 | - wai
69 | - wai-extra
70 | - warp
71 | when:
72 | - condition: flag(servant-spec)
73 | cpp-options: -DSERVANT_SPEC
74 |
75 | flags:
76 | servant-spec:
77 | description: Test ocaml-export against a servant server. Internal test use only.
78 | manual: True
79 | default: False
80 |
--------------------------------------------------------------------------------
/scratch.txt:
--------------------------------------------------------------------------------
1 | https://hackage.haskell.org/package/base-4.10.1.0/docs/Type-Reflection.html
2 |
3 | proxyToTypeRep :: forall a. (Typeable a) => Proxy a -> TypeRep a
4 | proxyToTypeRep Proxy = typeRep @a
5 |
6 | typeRepKind $ proxyToTypeRep (Proxy :: Proxy Maybe)
7 |
--------------------------------------------------------------------------------
/src/OCaml/Export.hs:
--------------------------------------------------------------------------------
1 | {-|
2 | Module : OCaml.Export
3 | Description : Export everything from one module
4 | Copyright : Plow Technologies, 2017
5 | License : BSD3
6 | Maintainer : mchaver@gmail.com
7 | Stability : experimental
8 |
9 | -}
10 |
11 | module OCaml.Export
12 | ( OCamlPackage
13 | , NoDependency
14 | , OCamlModule
15 | , OCamlSubModule
16 | , OCamlTypeInFile
17 | , HaskellTypeName
18 |
19 | , PackageOptions (..)
20 | , defaultPackageOptions
21 | , SpecOptions (..)
22 | , defaultSpecOptions
23 |
24 | , EmbeddedOCamlFiles (..)
25 |
26 | , mkPackage
27 | , mkFiles
28 | , mkOCamlTypeMetaData
29 |
30 | -- OCaml.BuckleScript.Types
31 | , OCamlType (..)
32 | , typeableToOCamlType
33 | , TypeParameterRef0(..)
34 | , TypeParameterRef1(..)
35 | , TypeParameterRef2(..)
36 | , TypeParameterRef3(..)
37 | , TypeParameterRef4(..)
38 | , TypeParameterRef5(..)
39 |
40 | -- servant spec
41 | , mkOCamlSpecServer
42 | , MkOCamlSpecAPI
43 | , mkGoldenFiles
44 | , runGoldenSpec
45 |
46 | -- re-export
47 | , Proxy (..)
48 | , (:>)
49 | , (:<|>) (..)
50 | , Application
51 | , Server
52 | , serve
53 |
54 | ) where
55 |
56 | import Data.Proxy (Proxy (..))
57 |
58 | import OCaml.BuckleScript.Types
59 |
60 | import OCaml.BuckleScript.Internal.Module
61 | import OCaml.BuckleScript.Internal.Package
62 | import OCaml.BuckleScript.Internal.Spec
63 |
64 | import Servant (Application, Server, serve)
65 | import Servant.API ((:>), (:<|>) (..))
66 |
--------------------------------------------------------------------------------
/stack.yaml:
--------------------------------------------------------------------------------
1 | resolver: lts-11.20
2 |
3 | packages:
4 | - .
5 |
6 | extra-deps:
7 | - hspec-golden-aeson-0.6.0.0
8 | - quickcheck-arbitrary-adt-0.3.0.0
9 |
10 | flags: {}
11 |
12 | extra-package-dbs: []
13 |
--------------------------------------------------------------------------------
/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # file: test.sh
3 |
4 | stack build
5 | stack test --no-run-tests
6 | stack test &
7 | servant_pid=$!
8 | sleep 5
9 |
10 | # we store the lib so no need to build
11 | npm install --prefix test/interface/golden
12 | npm run build --prefix test/interface/golden
13 | npm run test --prefix test/interface/golden
14 |
15 | kill -9 $servant_pid
16 |
--------------------------------------------------------------------------------
/test/FileApp.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE DataKinds #-}
2 | {-# LANGUAGE TemplateHaskell #-}
3 |
4 | module FileApp where
5 | -- containers
6 | import qualified Data.Map as Map
7 | -- hspec
8 | import Test.Hspec
9 | -- servant-server
10 | import Servant
11 | -- ocaml-export
12 | import OCaml.Export
13 | import File
14 | import Util
15 |
16 | $(mkOCamlSpecServer "FilePackage" (Proxy :: Proxy FilePackage))
17 |
18 | fileMap :: Map.Map String EmbeddedOCamlFiles
19 | fileMap = Map.fromList $(mkFiles True False (Proxy :: Proxy FilePackage))
20 |
21 | compareInterfaceFiles :: FilePath -> SpecWith ()
22 | compareInterfaceFiles = compareFiles "test/interface" "file" True
23 |
24 | spec :: Spec
25 | spec = do
26 | runIO $ mkGoldenFiles (Proxy :: Proxy FilePackage) 10 "test/interface/golden/golden/file"
27 | -- runGoldenSpec (Proxy :: Proxy FilePackage) 10 "test/interface/golden/golden/file"
28 | let dir = "test/interface/temp"
29 |
30 | -- create spec to be tested against servant
31 | runIO $
32 | mkPackage
33 | (Proxy :: Proxy FilePackage)
34 | (PackageOptions dir "file" fileMap True $
35 | Just $ SpecOptions "__tests__/file-servant" "golden/file" (Just "http://localhost:8083"))
36 |
37 | -- create spec to be tested against files only
38 | runIO $
39 | mkPackage
40 | (Proxy :: Proxy FilePackage)
41 | (PackageOptions dir "file" fileMap True $
42 | Just $ SpecOptions "__tests__/file" "golden/file" Nothing)
43 |
44 | describe "OCaml Declaration with Interface: Product Types" $
45 | compareInterfaceFiles "File"
46 |
--------------------------------------------------------------------------------
/test/Options.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE DeriveAnyClass #-}
2 | {-# LANGUAGE DeriveGeneric #-}
3 | {-# LANGUAGE OverloadedStrings #-}
4 |
5 | module Options where
6 |
7 | {-
8 | import Data.Aeson (FromJSON, ToJSON)
9 | import Data.Aeson.Types hiding (Options)
10 | import Data.Char (toUpper,toLower)
11 | import Data.Monoid ((<>))
12 | import Data.Proxy
13 | import Data.Text (Text)
14 | import Data.Time
15 | import Data.Time.Clock.POSIX
16 | import GHC.Generics
17 | import OCaml.Export hiding (Options,defaultOptions)
18 | import qualified OCaml.Export as OCaml (Options,defaultOptions)
19 | import Test.Hspec
20 | import Test.QuickCheck
21 | import Test.QuickCheck.Arbitrary.ADT
22 | import Test.Aeson.Internal.ADT.GoldenSpecs
23 | import Util
24 |
25 |
26 | testOptionsInterface = testOCamlTypeWithInterface Options
27 |
28 | mkTestOCaml :: OCamlType a => Text -> a -> OCamlInterface
29 | mkTestOCaml modul = mkOCamlInterfaceWithSpec "http://localhost:8081" "__tests__/golden/" modul
30 |
31 | fieldUpperOptions = defaultOptions { fieldLabelModifier = map toUpper }
32 |
33 | constructorLowerOptions = defaultOptions { constructorTagModifier = map toLower }
34 |
35 | oo = OCaml.defaultOptions {aesonOptions = fieldUpperOptions }
36 | ii = OCaml.defaultOptions {aesonOptions = constructorLowerOptions }
37 |
38 | spec :: Spec
39 | spec = do
40 | describe "OCaml Declaration with Interface: Types with Aeson Options" $ do
41 | testOptionsInterface "Person" (mkOCamlInterfaceWithOptions oo (Proxy :: Proxy Person))
42 | testOptionsInterface "NameOrIdNumber" (mkOCamlInterfaceWithOptions ii (Proxy :: Proxy NameOrIdNumber))
43 |
44 | data Person = Person
45 | { id :: Int
46 | , name :: Maybe String
47 | , created :: UTCTime
48 | } deriving (Show, Eq, Generic, OCamlType)
49 |
50 | instance Arbitrary Person where
51 | arbitrary = Person <$> arbitrary <*> arbitrary <*> arbitrary
52 |
53 | instance ToADTArbitrary Person
54 |
55 | instance ToJSON Person where
56 | toJSON = genericToJSON fieldUpperOptions
57 |
58 | instance FromJSON Person where
59 | parseJSON = genericParseJSON fieldUpperOptions
60 |
61 | data NameOrIdNumber = Name String | IdNumber Int
62 | deriving (Show, Eq, Generic, OCamlType)
63 |
64 | instance ToJSON NameOrIdNumber where
65 | toJSON = genericToJSON constructorLowerOptions
66 |
67 | instance FromJSON NameOrIdNumber where
68 | parseJSON = genericParseJSON constructorLowerOptions
69 | -}
70 |
--------------------------------------------------------------------------------
/test/ProductApp.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE TemplateHaskell #-}
2 |
3 | module ProductApp where
4 |
5 | import OCaml.Export
6 | import Product
7 | -- containers
8 | import qualified Data.Map as Map
9 | -- hspec
10 | import Test.Hspec
11 |
12 | fileMap :: Map.Map String EmbeddedOCamlFiles
13 | fileMap = Map.fromList $(mkFiles True False (Proxy :: Proxy ProductPackage))
14 |
15 | $(mkOCamlSpecServer "ProductPackage" (Proxy :: Proxy ProductPackage))
16 |
17 | spec :: Spec
18 | spec = do
19 | runIO $ mkGoldenFiles (Proxy :: Proxy ProductPackage) 10 "test/interface/golden/golden/product"
20 | runGoldenSpec (Proxy :: Proxy ProductPackage) 10 "test/interface/golden/golden/product"
21 |
22 | let dir = "test/interface/temp"
23 |
24 | -- create spec to be tested against servant
25 | runIO $
26 | mkPackage
27 | (Proxy :: Proxy ProductPackage)
28 | (PackageOptions dir "product" fileMap True $
29 | Just $
30 | SpecOptions
31 | "__tests__/product-servant"
32 | "golden/product"
33 | (Just "http://localhost:8081"))
34 |
35 | -- create spec to be tested against files only
36 | runIO $
37 | mkPackage
38 | (Proxy :: Proxy ProductPackage)
39 | (PackageOptions dir "product" fileMap True $
40 | Just $
41 | SpecOptions
42 | "__tests__/product"
43 | "golden/product"
44 | Nothing)
45 |
46 | describe "OCaml Declaration with Interface: Product Types" $ do
47 | compareInterfaceFiles "Person"
48 | compareInterfaceFiles "Company"
49 | compareInterfaceFiles "Card"
50 | compareInterfaceFiles "OneTypeParameter"
51 | compareInterfaceFiles "TwoTypeParameters"
52 | compareInterfaceFiles "ThreeTypeParameters"
53 | compareInterfaceFiles "SubTypeParameter"
54 | compareInterfaceFiles "UnnamedProduct"
55 | compareInterfaceFiles "ComplexProduct"
56 | compareInterfaceFiles "Wrapper"
57 | compareInterfaceFiles "Box"
58 | compareInterfaceFiles "Key"
59 |
--------------------------------------------------------------------------------
/test/Spec.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE CPP #-}
2 | {-# LANGUAGE DataKinds #-}
3 | {-# LANGUAGE KindSignatures #-}
4 | {-# LANGUAGE OverloadedStrings #-}
5 | {-# LANGUAGE PolyKinds #-}
6 | {-# LANGUAGE RankNTypes #-}
7 | {-# LANGUAGE TemplateHaskell #-}
8 | {-# LANGUAGE TypeOperators #-}
9 |
10 | -- base
11 | import Data.Monoid ((<>))
12 | -- hspec
13 | import Test.Hspec
14 | -- ocaml-export
15 | import qualified Dependency as D
16 | import qualified FileApp as File
17 | import qualified Product as Product
18 | import qualified ProductApp as Product
19 | import qualified Sum as Sum
20 | import OCaml.Export
21 |
22 | #ifdef SERVANT_SPEC
23 | import Control.Concurrent (forkIO)
24 | import SumApp
25 | -- warp
26 | import Network.Wai.Handler.Warp
27 | #endif
28 |
29 | main :: IO ()
30 | main = do
31 | hspec Product.spec
32 | hspec Sum.spec
33 | hspec File.spec
34 | hspec D.spec
35 |
36 | hspec $
37 | describe "mkOCamlTypeMetaData" $
38 | it "mkOCamlTypeMetaData on package A and B should equal mkOCamlTypeMetaData on B which has A as a dependency" $
39 | (mkOCamlTypeMetaData (Proxy :: Proxy Product.ProductPackage)) <> (mkOCamlTypeMetaData (Proxy :: Proxy D.DependencyPackageWithoutProduct))
40 | `shouldBe` mkOCamlTypeMetaData (Proxy :: Proxy D.DependencyPackage)
41 |
42 | #ifdef SERVANT_SPEC
43 | _ <- forkIO $ run 8081 Product.productPackageApp
44 | _ <- forkIO $ run 8082 sumPackageApp
45 | run 8083 File.filePackageApp
46 | #endif
47 |
--------------------------------------------------------------------------------
/test/SumApp.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE TemplateHaskell #-}
2 |
3 | module SumApp where
4 |
5 | import OCaml.Export
6 | import Sum
7 |
8 | $(mkOCamlSpecServer "SumPackage" (Proxy :: Proxy SumPackage))
9 |
--------------------------------------------------------------------------------
/test/Util.hs:
--------------------------------------------------------------------------------
1 | {-# OPTIONS_GHC -fno-warn-orphans #-}
2 |
3 | module Util where
4 | -- base
5 | import Data.Monoid ((<>))
6 | import Data.Time
7 | -- text
8 | import qualified Data.Text.IO as T
9 | -- filepath
10 | import System.FilePath.Posix ((>))
11 | -- hspec
12 | import Test.Hspec
13 | -- QuickCheck
14 | import Test.QuickCheck
15 |
16 | instance Arbitrary UTCTime where
17 | arbitrary =
18 | UTCTime <$> (ModifiedJulianDay <$> (2000 +) <$> arbitrary)
19 | <*> pure 1.011
20 | -- <*> (fromRational . toRational . (\f -> fromInteger $ round $ f * (10^2) / (10.0^^2)) <$> choose (0:: Double, 86400))
21 |
22 | data ADT
23 | = Options
24 |
25 | adtToPath :: ADT -> FilePath
26 | adtToPath Options = "options"
27 |
28 | compareFiles :: FilePath -> FilePath -> Bool -> FilePath -> SpecWith ()
29 | compareFiles rootDir categoryDir compareInterfaceAndSpecFiles typeName =
30 | it typeName $ do
31 | automated <- T.readFile (testPath > typeName <> ".ml")
32 | handWritten <- T.readFile (goldenPath > typeName <> ".ml")
33 | automated `shouldBe` handWritten
34 | if compareInterfaceAndSpecFiles
35 | then do
36 | automatedI <- T.readFile (testPath > typeName <> ".mli")
37 | handWrittenI <- T.readFile (goldenPath > typeName <> ".mli")
38 | automatedI `shouldBe` handWrittenI
39 |
40 | automatedS <- T.readFile (testSpecPath > typeName <> "_spec" <> ".ml")
41 | handWrittenS <- T.readFile (goldenSpecPath > typeName <> "_spec" <> ".ml")
42 | automatedS `shouldBe` handWrittenS
43 | else pure ()
44 | where
45 | testPath = rootDir > "temp" > categoryDir
46 | goldenPath = rootDir > "golden" > categoryDir
47 | testSpecPath = rootDir > "temp" > "__tests__" > categoryDir
48 | goldenSpecPath = rootDir > "golden" > "__tests__" > categoryDir
49 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/file-servant/File_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | File.decodePerson
4 | File.encodePerson
5 | "person"
6 | "http://localhost:8083/File/Person"
7 | "golden/file/Person";
8 |
9 | AesonSpec.sampleGoldenAndServerSpec
10 | File.decodeAutomobile
11 | File.encodeAutomobile
12 | "automobile"
13 | "http://localhost:8083/File/Automobile"
14 | "golden/file/Automobile";
15 |
16 | AesonSpec.sampleGoldenAndServerSpec
17 | File.decodeBusiness
18 | File.encodeBusiness
19 | "business"
20 | "http://localhost:8083/File/Business"
21 | "golden/file/Business";
22 |
23 | AesonSpec.sampleGoldenAndServerSpec
24 | (File.decodeWrapper AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
25 | (File.encodeWrapper Aeson.Encode.int Aeson.Encode.int)
26 | "wrapper"
27 | "http://localhost:8083/File/Wrapper"
28 | "golden/file/Wrapper";
29 |
30 | AesonSpec.sampleGoldenAndServerSpec
31 | File.decodeAutoDependingOnManual
32 | File.encodeAutoDependingOnManual
33 | "autoDependingOnManual"
34 | "http://localhost:8083/File/AutoDependingOnManual"
35 | "golden/file/AutoDependingOnManual";
36 |
37 | AesonSpec.sampleGoldenAndServerSpec
38 | File.decodeNonGenericType
39 | File.encodeNonGenericType
40 | "nonGenericType"
41 | "http://localhost:8083/File/NonGenericType"
42 | "golden/file/NonGenericType";
43 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/file/File_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | File.decodePerson
4 | File.encodePerson
5 | "person"
6 | "golden/file/Person";
7 |
8 | AesonSpec.goldenDirSpec
9 | File.decodeAutomobile
10 | File.encodeAutomobile
11 | "automobile"
12 | "golden/file/Automobile";
13 |
14 | AesonSpec.goldenDirSpec
15 | File.decodeBusiness
16 | File.encodeBusiness
17 | "business"
18 | "golden/file/Business";
19 |
20 | AesonSpec.goldenDirSpec
21 | (File.decodeWrapper AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
22 | (File.encodeWrapper Aeson.Encode.int Aeson.Encode.int)
23 | "wrapper"
24 | "golden/file/Wrapper";
25 |
26 | AesonSpec.goldenDirSpec
27 | File.decodeAutoDependingOnManual
28 | File.encodeAutoDependingOnManual
29 | "autoDependingOnManual"
30 | "golden/file/AutoDependingOnManual";
31 |
32 | AesonSpec.goldenDirSpec
33 | File.decodeNonGenericType
34 | File.encodeNonGenericType
35 | "nonGenericType"
36 | "golden/file/NonGenericType";
37 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/Card_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | Card.decodeSuit
4 | Card.encodeSuit
5 | "suit"
6 | "http://localhost:8081/Card/Suit"
7 | "golden/product/Suit";
8 |
9 | AesonSpec.sampleGoldenAndServerSpec
10 | Card.decodeCard
11 | Card.encodeCard
12 | "card"
13 | "http://localhost:8081/Card/Card"
14 | "golden/product/Card";
15 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/Company_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | Company.decodeCompany
4 | Company.encodeCompany
5 | "company"
6 | "http://localhost:8081/Company/Company"
7 | "golden/product/Company";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/ComplexProduct_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | ComplexProduct.decodeSimple
4 | ComplexProduct.encodeSimple
5 | "simple"
6 | "http://localhost:8081/ComplexProduct/Simple"
7 | "golden/product/Simple";
8 |
9 | AesonSpec.sampleGoldenAndServerSpec
10 | ComplexProduct.decodeComplexProduct
11 | ComplexProduct.encodeComplexProduct
12 | "complexProduct"
13 | "http://localhost:8081/ComplexProduct/ComplexProduct"
14 | "golden/product/ComplexProduct";
15 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/CustomOption_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec CustomOption.decodeCompany2 CustomOption.encodeCompany2 "company2" "http://localhost:8081/CustomOption/Company2" "golden/product/Company2";
3 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/OneTypeParameter_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | (OneTypeParameter.decodeOneTypeParameter AesonSpec.decodeIntWithResult)
4 | (OneTypeParameter.encodeOneTypeParameter Aeson.Encode.int)
5 | "oneTypeParameter"
6 | "http://localhost:8081/OneTypeParameter/OneTypeParameter"
7 | "golden/product/OneTypeParameter";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/Person_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | Person.decodePerson
4 | Person.encodePerson
5 | "person"
6 | "http://localhost:8081/Person/Person"
7 | "golden/product/Person";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/SimpleChoice_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec SimpleChoice.decodeSimpleChoice SimpleChoice.encodeSimpleChoice "simpleChoice" "http://localhost:8081/SimpleChoice/SimpleChoice" "golden/product/SimpleChoice";
3 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/SubTypeParameter_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | (SubTypeParameter.decodeSubTypeParameter AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
4 | (SubTypeParameter.encodeSubTypeParameter Aeson.Encode.int Aeson.Encode.int Aeson.Encode.int)
5 | "subTypeParameter"
6 | "http://localhost:8081/SubTypeParameter/SubTypeParameter"
7 | "golden/product/SubTypeParameter";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/ThreeTypeParameters_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | (ThreeTypeParameters.decodeThree AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
4 | (ThreeTypeParameters.encodeThree Aeson.Encode.int Aeson.Encode.int Aeson.Encode.int)
5 | "three"
6 | "http://localhost:8081/ThreeTypeParameters/Three"
7 | "golden/product/Three";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/TwoTypeParameters_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | (TwoTypeParameters.decodeTwoTypeParameters AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
4 | (TwoTypeParameters.encodeTwoTypeParameters Aeson.Encode.int Aeson.Encode.int)
5 | "twoTypeParameters"
6 | "http://localhost:8081/TwoTypeParameters/TwoTypeParameters"
7 | "golden/product/TwoTypeParameters";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product-servant/UnnamedProduct_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | UnnamedProduct.decodeUnnamedProduct
4 | UnnamedProduct.encodeUnnamedProduct
5 | "unnamedProduct"
6 | "http://localhost:8081/UnnamedProduct/UnnamedProduct"
7 | "golden/product/UnnamedProduct";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/Box_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | (Box.decodeInnerBox AesonSpec.decodeIntWithResult)
4 | (Box.encodeInnerBox Aeson.Encode.int)
5 | "innerBox"
6 | "golden/product/InnerBox";
7 |
8 | AesonSpec.goldenDirSpec
9 | Box.decodeOuterBox
10 | Box.encodeOuterBox
11 | "outerBox"
12 | "golden/product/OuterBox";
13 |
14 | AesonSpec.goldenDirSpec
15 | Box.decodeAuditAction
16 | Box.encodeAuditAction
17 | "auditAction"
18 | "golden/product/AuditAction";
19 |
20 | AesonSpec.goldenDirSpec
21 | (Box.decodeAuditModel AesonSpec.decodeIntWithResult)
22 | (Box.encodeAuditModel Aeson.Encode.int)
23 | "auditModel"
24 | "golden/product/AuditModel";
25 |
26 | AesonSpec.goldenDirSpec
27 | Box.decodeUser
28 | Box.encodeUser
29 | "user"
30 | "golden/product/User";
31 |
32 | AesonSpec.goldenDirSpec
33 | Box.decodeUserAudit
34 | Box.encodeUserAudit
35 | "userAudit"
36 | "golden/product/UserAudit";
37 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/Card_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | Card.decodeSuit
4 | Card.encodeSuit
5 | "suit"
6 | "golden/product/Suit";
7 |
8 | AesonSpec.goldenDirSpec
9 | Card.decodeCard
10 | Card.encodeCard
11 | "card"
12 | "golden/product/Card";
13 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/Company_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | Company.decodeCompany
4 | Company.encodeCompany
5 | "company"
6 | "golden/product/Company";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/ComplexProduct_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | ComplexProduct.decodeSimple
4 | ComplexProduct.encodeSimple
5 | "simple"
6 | "golden/product/Simple";
7 |
8 | AesonSpec.goldenDirSpec
9 | ComplexProduct.decodeComplexProduct
10 | ComplexProduct.encodeComplexProduct
11 | "complexProduct"
12 | "golden/product/ComplexProduct";
13 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/CustomOption_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | CustomOption.decodeCompany2
4 | CustomOption.encodeCompany2
5 | "company2"
6 | "golden/product/Company2";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/Key_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | Key.decodeSqlKey
4 | Key.encodeSqlKey
5 | "sqlKey"
6 | "golden/product/SqlKey";
7 |
8 | AesonSpec.goldenDirSpec
9 | Key.decodeUserId
10 | Key.encodeUserId
11 | "userId"
12 | "golden/product/UserId";
13 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/OneTypeParameter_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | (OneTypeParameter.decodeOneTypeParameter AesonSpec.decodeIntWithResult)
4 | (OneTypeParameter.encodeOneTypeParameter Aeson.Encode.int)
5 | "oneTypeParameter"
6 | "golden/product/OneTypeParameter";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/Person_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | Person.decodePerson
4 | Person.encodePerson
5 | "person"
6 | "golden/product/Person";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/SimpleChoice_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | SimpleChoice.decodeSimpleChoice
4 | SimpleChoice.encodeSimpleChoice
5 | "simpleChoice"
6 | "golden/product/SimpleChoice";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/SubTypeParameter_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | (SubTypeParameter.decodeSubTypeParameter AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
4 | (SubTypeParameter.encodeSubTypeParameter Aeson.Encode.int Aeson.Encode.int Aeson.Encode.int)
5 | "subTypeParameter"
6 | "golden/product/SubTypeParameter";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/ThreeTypeParameters_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | (ThreeTypeParameters.decodeThree AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
4 | (ThreeTypeParameters.encodeThree Aeson.Encode.int Aeson.Encode.int Aeson.Encode.int)
5 | "three"
6 | "golden/product/Three";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/TwoTypeParameters_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | (TwoTypeParameters.decodeTwoTypeParameters AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
4 | (TwoTypeParameters.encodeTwoTypeParameters Aeson.Encode.int Aeson.Encode.int)
5 | "twoTypeParameters"
6 | "golden/product/TwoTypeParameters";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/product/UnnamedProduct_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | UnnamedProduct.decodeUnnamedProduct
4 | UnnamedProduct.encodeUnnamedProduct
5 | "unnamedProduct"
6 | "golden/product/UnnamedProduct";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum-servant/NameOrIdNumber_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | NameOrIdNumber.decodeNameOrIdNumber
4 | NameOrIdNumber.encodeNameOrIdNumber
5 | "nameOrIdNumber"
6 | "http://localhost:8082/NameOrIdNumber/NameOrIdNumber"
7 | "golden/sum/NameOrIdNumber";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum-servant/NewType_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | NewType.decodeNewType
4 | NewType.encodeNewType
5 | "newType"
6 | "http://localhost:8082/NewType/NewType"
7 | "golden/sum/NewType";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum-servant/OnOrOff_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | OnOrOff.decodeOnOrOff
4 | OnOrOff.encodeOnOrOff
5 | "onOrOff"
6 | "http://localhost:8082/OnOrOff/OnOrOff"
7 | "golden/sum/OnOrOff";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum-servant/Result_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | (Result.decodeResult AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
4 | (Result.encodeResult Aeson.Encode.int Aeson.Encode.int)
5 | "result"
6 | "http://localhost:8082/Result/Result"
7 | "golden/sum/Result";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum-servant/SingleSum_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | SingleSum.decodeSingleSum
4 | SingleSum.encodeSingleSum
5 | "nameOrIdNumber"
6 | "http://localhost:8082/SingleSum/SingleSum"
7 | "golden/sum/SingleSum";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum-servant/SumVariant_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | SumVariant.decodeSumVariant
4 | SumVariant.encodeSumVariant
5 | "sumVariant"
6 | "http://localhost:8082/SumVariant/SumVariant"
7 | "golden/sum/SumVariant";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum-servant/SumWithRecord_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | SumWithRecord.decodeSumWithRecord
4 | SumWithRecord.encodeSumWithRecord
5 | "sumWithRecord"
6 | "http://localhost:8082/SumWithRecord/SumWithRecord"
7 | "golden/sum/SumWithRecord";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum-servant/WithTuple_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.sampleGoldenAndServerSpec
3 | WithTuple.decodeWithTuple
4 | WithTuple.encodeWithTuple
5 | "withTuple"
6 | "http://localhost:8082/WithTuple/WithTuple"
7 | "golden/sum/WithTuple";
8 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum/NameOrIdNumber_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | NameOrIdNumber.decodeNameOrIdNumber
4 | NameOrIdNumber.encodeNameOrIdNumber
5 | "nameOrIdNumber"
6 | "golden/sum/NameOrIdNumber";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum/NewType_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | NewType.decodeNewType
4 | NewType.encodeNewType
5 | "newType"
6 | "golden/sum/NewType";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum/OnOrOff_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | OnOrOff.decodeOnOrOff
4 | OnOrOff.encodeOnOrOff
5 | "onOrOff"
6 | "golden/sum/OnOrOff";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum/Result_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | (Result.decodeResult AesonSpec.decodeIntWithResult AesonSpec.decodeIntWithResult)
4 | (Result.encodeResult Aeson.Encode.int Aeson.Encode.int)
5 | "result"
6 | "golden/sum/Result";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum/SingleSum_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | SingleSum.decodeSingleSum
4 | SingleSum.encodeSingleSum
5 | "singleSum"
6 | "golden/sum/SingleSum";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum/SumVariant_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | SumVariant.decodeSumVariant
4 | SumVariant.encodeSumVariant
5 | "sumVariant"
6 | "golden/sum/SumVariant";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum/SumWithRecord_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | SumWithRecord.decodeSumWithRecord
4 | SumWithRecord.encodeSumWithRecord
5 | "sumWithRecord"
6 | "golden/sum/SumWithRecord";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/__tests__/sum/WithTuple_spec.ml:
--------------------------------------------------------------------------------
1 | let () =
2 | AesonSpec.goldenDirSpec
3 | WithTuple.decodeWithTuple
4 | WithTuple.encodeWithTuple
5 | "withTuple"
6 | "golden/sum/WithTuple";
7 |
--------------------------------------------------------------------------------
/test/interface/golden/bsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ocaml-export",
3 | "bsc-flags": ["-bs-no-version-header", "-bs-super-errors"],
4 | "bs-dependencies": ["bs-aeson"],
5 | "bs-dev-dependencies": ["bs-aeson", "bs-aeson-spec", "bs-node-fetch", "@glennsl/bs-jest"],
6 | "sources": [
7 | {
8 | "dir": "product",
9 | "subdirs": true
10 | },
11 | {
12 | "dir": "sum",
13 | "subdirs": true
14 | },
15 | {
16 | "dir": "file",
17 | "subdirs": true
18 | },
19 | {
20 | "dir": "__tests__/product",
21 | "subdirs": true,
22 | "type": "dev"
23 | },
24 | {
25 | "dir": "__tests__/sum",
26 | "subdirs": true,
27 | "type": "dev"
28 | },
29 | {
30 | "dir": "__tests__/file",
31 | "subdirs": true,
32 | "type": "dev"
33 | }
34 | /*
35 | ,{
36 | "dir": "__tests__/product-servant",
37 | "subdirs": true,
38 | "type": "dev"
39 | },
40 | {
41 | "dir": "__tests__/sum-servant",
42 | "subdirs": true,
43 | "type": "dev"
44 | },
45 | {
46 | "dir": "__tests__/file-servant",
47 | "subdirs": true,
48 | "type": "dev"
49 | }
50 | */
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/test/interface/golden/file/File.mli:
--------------------------------------------------------------------------------
1 | type person =
2 | { id : int
3 | ; name : (string) option
4 | }
5 |
6 | val encodePerson : person -> Js_json.t
7 |
8 | val decodePerson : Js_json.t -> (person, string) Belt.Result.t
9 |
10 |
11 | type automobile =
12 | { make : string
13 | ; model : string
14 | ; year : int
15 | }
16 |
17 | val encodeAutomobile : automobile -> Js_json.t
18 |
19 | val decodeAutomobile : Js_json.t -> (automobile, string) Belt.Result.t
20 |
21 | type business =
22 | { taxId : string
23 | ; owner : person
24 | ; employees : (person) list
25 | ; companyVehicle : (automobile) option
26 | }
27 |
28 | val encodeBusiness : business -> Js_json.t
29 |
30 | val decodeBusiness : Js_json.t -> (business, string) Belt.Result.t
31 |
32 |
33 | type ('a, 'b) wrapper =
34 | { wrapperA : 'a
35 | ; wrapperB : 'b
36 | ; wrapperC : string
37 | }
38 |
39 | val encodeWrapper : ('a -> Js_json.t) -> ('b -> Js_json.t) -> ('a, 'b) wrapper -> Js_json.t
40 |
41 | val decodeWrapper : (Js_json.t -> ('a, string) Belt.Result.t) -> (Js_json.t -> ('b, string) Belt.Result.t) -> Js_json.t -> (('a, 'b) wrapper, string) Belt.Result.t
42 |
43 |
44 | type autoDependingOnManual =
45 | { abc : string
46 | ; bbBusiness : business
47 | }
48 |
49 | val encodeAutoDependingOnManual : autoDependingOnManual -> Js_json.t
50 |
51 | val decodeAutoDependingOnManual : Js_json.t -> (autoDependingOnManual, string) Belt.Result.t
52 |
53 | type nonGenericType =
54 | { ngA : string
55 | ; ngB : int
56 | }
57 |
58 | val encodeNonGenericType : nonGenericType -> Js_json.t
59 |
60 | val decodeNonGenericType : Js_json.t -> (nonGenericType, string) Belt.Result.t
61 |
62 |
--------------------------------------------------------------------------------
/test/interface/golden/golden/file/Automobile/Automobile.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -252353446794561167,
3 | "samples": [
4 | {
5 | "year": -5,
6 | "model": "à¡"
18 | },
19 | {
20 | "year": 26,
21 | "model": "4l\u001f?C\u0007\u001exqNGU\u001b_b;_b71\nÿ",
22 | "make": "â²Mb\u0015\u001bÞ-Eo"
23 | },
24 | {
25 | "year": 17,
26 | "model": "",
27 | "make": ".$\u001cfW¶\u0016\u0001WQu"
28 | },
29 | {
30 | "year": 3,
31 | "model": "6\u0018B\u000f\u001a¸½`.V§",
32 | "make": ">PàBlº Ç"
33 | },
34 | {
35 | "year": 23,
36 | "model": "<{Ö«·\u0001¢$bPV",
37 | "make": "m?&X´ö»&27-\u000e?b,#\u000c=s\u000e\u0016A\u0005z\u001a-c"
38 | },
39 | {
40 | "year": -4,
41 | "model": "\u0011\u001a\u000f#S{aY¶@:y\u0001 ò\u0002u'\u000fÑE",
42 | "make": "ÊNÿ*j×\u0004[Dl\u0005\u0019"
43 | },
44 | {
45 | "year": -5,
46 | "model": "*\u0001DN\u000e[ûV0@MBå\u0003\u0000\u0004W\n
\u0000\u001emh",
47 | "make": "ëJ*eÓþCâ}H4X\u001a}hcú$'\u001b3Rrh\u001a"
48 | },
49 | {
50 | "year": 1,
51 | "model": "H\u000b\u0016*\u0019\u00051G\u0003\u0006Qw3¾\n8~s,\u000c",
52 | "make": "Ò\u001aWZ67D®½ \u0013_\u0008mjE9"
53 | }
54 | ]
55 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/file/NonGenericType/NonGenericType.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 4386779205279759687,
3 | "samples": [
4 | {
5 | "ngA": "á\u0012Oe?",
6 | "ngB": 16
7 | },
8 | {
9 | "ngA": "k·vZ{",
10 | "ngB": -16
11 | },
12 | {
13 | "ngA": "d=\u0005UK\u001aeéØt\u0004\räíhT\u0013aw:ö\u0015Dt'",
14 | "ngB": -13
15 | },
16 | {
17 | "ngA": "\u0001",
18 | "ngB": -2
19 | },
20 | {
21 | "ngA": "P\u001b6?n*or/!6Ó]Ré\u0008òK\u000cNA/ý",
22 | "ngB": -28
23 | },
24 | {
25 | "ngA": "\u0019q\u0005",
26 | "ngB": 22
27 | },
28 | {
29 | "ngA": "\u0014u\u0006oL{²ç\u001d@s\u0013\u0003\u0005\u0005t",
30 | "ngB": 13
31 | },
32 | {
33 | "ngA": "\"I(>!Q\u001auh\u0014¥\u0016¯©`Á3-r\u0018dE\u0013L",
34 | "ngB": -1
35 | },
36 | {
37 | "ngA": "\u0016i\"®p\nkH\"\u001aÎ>bAhn\u000caÀn³",
38 | "ngB": -29
39 | },
40 | {
41 | "ngA": "»D\u000bKï ë4\u0016V;\u0003#³Õ\u001bf\u0019.",
42 | "ngB": -25
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/file/Person/Person.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 7903380226979960503,
3 | "samples": [
4 | {
5 | "name": "
`\u000c*e}M~[:o)\u001b6H@",
6 | "id": 6
7 | },
8 | {
9 | "name": "z\u0014\u001c1Ò+q\u0003èï\u0007\u0010'j|¦:\u0007^DK\u001dsw\u001aY*",
10 | "id": 23
11 | },
12 | {
13 | "name": "v3ÓÚNg\u001bäT\n\u000e\u001bÙÒQ{\u0015M\u0004@~Õ",
14 | "id": -5
15 | },
16 | {
17 | "name": "99\u0013=L\u001aPF/p/(&ã\u0010(Íq,,",
18 | "id": 24
19 | },
20 | {
21 | "name": "¼5\u0011c`EèÔ]\u0007WnS/Tb\u0004%}R\u00139 ¸",
22 | "id": -15
23 | },
24 | {
25 | "name": "\u0014Y¯!T2\u0008âû\u0015µ%µ~Mø{\u000b\u00126VlNQrDÔÚ`",
26 | "id": -16
27 | },
28 | {
29 | "name": "",
30 | "id": -17
31 | },
32 | {
33 | "name": null,
34 | "id": 30
35 | },
36 | {
37 | "name": "M\u000c\"[\u0014\u001dA<\u0005\u001c×\u001e-c¦\u0019",
38 | "id": -26
39 | },
40 | {
41 | "name": null,
42 | "id": -7
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/file/Wrapper/Wrapper.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -6868269631152827663,
3 | "samples": [
4 | {
5 | "wrapperC": "3Hÿ¤-|\u000bZÊ&G2\r6F",
6 | "wrapperB": 9,
7 | "wrapperA": -18
8 | },
9 | {
10 | "wrapperC": "ùÀF[\u0017\u0002",
11 | "wrapperB": 21,
12 | "wrapperA": -29
13 | },
14 | {
15 | "wrapperC": "ì;â,.\u000fnD÷Tyh\u0016Vvµ2WÕ\u001d·\u001a*)\u000f",
16 | "wrapperB": -15,
17 | "wrapperA": -18
18 | },
19 | {
20 | "wrapperC": "û6a\u001d\u00195;",
21 | "wrapperB": -9,
22 | "wrapperA": -5
23 | },
24 | {
25 | "wrapperC": "t<-\tvU1\u0014\u001b-Û",
26 | "wrapperB": 28,
27 | "wrapperA": -19
28 | },
29 | {
30 | "wrapperC": "¬\u0015?¯\u0017",
31 | "wrapperB": 10,
32 | "wrapperA": 23
33 | },
34 | {
35 | "wrapperC": "JI\u0000V\u0017ï\u0006\u001eU#\u0000D\u0004Q",
36 | "wrapperB": 10,
37 | "wrapperA": -4
38 | },
39 | {
40 | "wrapperC": "\")}>\t@8\u001bN\nÁ[åGÃ\u001b",
46 | "wrapperB": -1,
47 | "wrapperA": -14
48 | },
49 | {
50 | "wrapperC": "p#8l",
51 | "wrapperB": -6,
52 | "wrapperA": 25
53 | }
54 | ]
55 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/AuditAction/Create.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -5501544309030902648,
3 | "samples": [
4 | "Create",
5 | "Create",
6 | "Create",
7 | "Create",
8 | "Create",
9 | "Create",
10 | "Create",
11 | "Create",
12 | "Create",
13 | "Create"
14 | ]
15 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/AuditAction/Delete.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 5301502580092110989,
3 | "samples": [
4 | "Delete",
5 | "Delete",
6 | "Delete",
7 | "Delete",
8 | "Delete",
9 | "Delete",
10 | "Delete",
11 | "Delete",
12 | "Delete",
13 | "Delete"
14 | ]
15 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/AuditAction/Update.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 8067707645285678060,
3 | "samples": [
4 | "Update",
5 | "Update",
6 | "Update",
7 | "Update",
8 | "Update",
9 | "Update",
10 | "Update",
11 | "Update",
12 | "Update",
13 | "Update"
14 | ]
15 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/AuditModel/AuditModel.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -4331257071399132001,
3 | "samples": [
4 | {
5 | "editedOn": "14+Rh~M0>*\u00047\u0003\u0010V",
6 | "originalId": ")%V__v5Z-\u00167v",
7 | "auditModel": -24,
8 | "editedBy": "J!",
9 | "auditAction": "Update"
10 | },
11 | {
12 | "editedOn": "懴\u0003cS+\u000eN\r",
13 | "originalId": "\u0001[\u0017{=uP!22z",
14 | "auditModel": -22,
15 | "editedBy": "3{\u0000!\u000c.1et\u0001kn\"\u000f\u0016@Y1%F}a\u001f",
16 | "auditAction": "Create"
17 | },
18 | {
19 | "editedOn": "]\u0013jtu}6)^Q.",
20 | "originalId": "P\u00038\"t4𧆛9C|iba'",
21 | "auditModel": -10,
22 | "editedBy": "jw𠶚",
23 | "auditAction": "Update"
24 | },
25 | {
26 | "editedOn": "d𣤗jR",
27 | "originalId": "\u0013Z𩕐u4\u0016\u0000\u0018;8𦱅\"]Tp뀢",
28 | "auditModel": 11,
29 | "editedBy": "{-\u000f?型Bt_^)FU\\\u0000",
30 | "auditAction": "Delete"
31 | },
32 | {
33 | "editedOn": "%\u001b.^ik\u0005wb~\u0007&O(\u0011gh%kN𡔔\u0015𲍲* ",
34 | "originalId": "Y*ay;R\u000c𔖰lm",
35 | "auditModel": 7,
36 | "editedBy": "\u0010\u000ew^'%𑰾Oq(DI<\n",
37 | "auditAction": "Create"
38 | },
39 | {
40 | "editedOn": "\u0008#z/IDx2𮂬Pw)\u0012b0~@ZX3",
41 | "originalId": "<\u0014>\u0004\u0019zglV-~7",
42 | "auditModel": -24,
43 | "editedBy": "`\u0001\u001e\u000eJu*\u001aWP",
44 | "auditAction": "Update"
45 | },
46 | {
47 | "editedOn": "b:WRH)c:\u000f\u0013",
48 | "originalId": "6B_\u001b&𪘛C&<\u0000",
49 | "auditModel": -15,
50 | "editedBy": "i-\u00082\\-\u0019 5#8M\u0008i\"R-$(𬗼NG",
51 | "auditAction": "Update"
52 | },
53 | {
54 | "editedOn": "",
55 | "originalId": "8usi=op\u001bp\u001f@\u001dnc\u000fc\u0018\u0018\u0006\u0004Or3\u0016",
56 | "auditModel": -27,
57 | "editedBy": "\u0018S\u0006\u000c93{",
58 | "auditAction": "Delete"
59 | },
60 | {
61 | "editedOn": "N44{+9𡈼𪆙u\u00121b",
62 | "originalId": "Rh G\u0004^\u000eXYR",
63 | "auditModel": -19,
64 | "editedBy": "hw\u0017𫼆9/\u0003\u000e[8(\u001ej*$K\u0019NynXKy",
65 | "auditAction": "Create"
66 | },
67 | {
68 | "editedOn": "^:𬉍<\u0019$}6\u0008",
29 | "id": 15
30 | }
31 | },
32 | {
33 | "address2": "\u001dL3\u001c\t)\u0005𬮚E\u001fv]7",
34 | "boss": null
35 | },
36 | {
37 | "address2": "a\u000e𗃐`H\u0016%㨠凷iX;\u001d|",
38 | "boss": {
39 | "created": "1864-06-06T00:00:01.011Z",
40 | "name": "A\u000f>$",
41 | "id": 11
42 | }
43 | },
44 | {
45 | "address2": "\u0002\u000bYs2\u0005\u0013y𓂥KjK\u000f\u0012=\u001dfF7{<",
46 | "boss": {
47 | "created": "1864-05-12T00:00:01.011Z",
48 | "name": ",f'=|]$\u000e\u001e\u0012#𰈙-y>\u0016",
49 | "id": -23
50 | }
51 | },
52 | {
53 | "address2": "S\u0015`R\u0016W\u0016;G:G\u0006.w",
54 | "boss": {
55 | "created": "1864-06-03T00:00:01.011Z",
56 | "name": "K@INb$0\u0003h\u0013\u001e+",
57 | "id": 30
58 | }
59 | },
60 | {
61 | "address2": "{8",
62 | "boss": null
63 | },
64 | {
65 | "address2": "q*~5]$s*\u0008+\n\u00192FBSjR\u00058]h",
66 | "boss": {
67 | "created": "1864-05-15T00:00:01.011Z",
68 | "name": "\u0006$\u0002N\"\u0000K\u0004iO\u0004`j]]6𧺘\u000cl86\u0016`Sr\u0013",
69 | "id": 30
70 | }
71 | }
72 | ]
73 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/ComplexWrapped/ComplexWrapped.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 8749844924866748307,
3 | "samples": [
4 | {
5 | "cw": {
6 | "wpa": {
7 | "Right": -27.08048962139064
8 | }
9 | }
10 | },
11 | {
12 | "cw": {
13 | "wpa": {
14 | "Left": null
15 | }
16 | }
17 | },
18 | {
19 | "cw": {
20 | "wpa": {
21 | "Left": "\u0006"
22 | }
23 | }
24 | },
25 | {
26 | "cw": {
27 | "wpa": {
28 | "Right": 26.11151959581339
29 | }
30 | }
31 | },
32 | {
33 | "cw": {
34 | "wpa": {
35 | "Left": null
36 | }
37 | }
38 | },
39 | {
40 | "cw": {
41 | "wpa": {
42 | "Left": "Z"
43 | }
44 | }
45 | },
46 | {
47 | "cw": {
48 | "wpa": {
49 | "Right": -28.62596124078363
50 | }
51 | }
52 | },
53 | {
54 | "cw": {
55 | "wpa": {
56 | "Right": 99.33759514062304
57 | }
58 | }
59 | },
60 | {
61 | "cw": {
62 | "wpa": {
63 | "Left": null
64 | }
65 | }
66 | },
67 | {
68 | "cw": {
69 | "wpa": {
70 | "Left": "q"
71 | }
72 | }
73 | }
74 | ]
75 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/EitherWrapped/EitherWrapped.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -3460743836191451419,
3 | "samples": [
4 | {
5 | "ew": {
6 | "wpa": {
7 | "Right": -12.413585643688497
8 | }
9 | }
10 | },
11 | {
12 | "ew": {
13 | "wpa": {
14 | "Right": -14.961549684281188
15 | }
16 | }
17 | },
18 | {
19 | "ew": {
20 | "wpa": {
21 | "Left": 19
22 | }
23 | }
24 | },
25 | {
26 | "ew": {
27 | "wpa": {
28 | "Right": -181.80462499555927
29 | }
30 | }
31 | },
32 | {
33 | "ew": {
34 | "wpa": {
35 | "Right": 19.11136304874505
36 | }
37 | }
38 | },
39 | {
40 | "ew": {
41 | "wpa": {
42 | "Left": 14
43 | }
44 | }
45 | },
46 | {
47 | "ew": {
48 | "wpa": {
49 | "Left": 27
50 | }
51 | }
52 | },
53 | {
54 | "ew": {
55 | "wpa": {
56 | "Right": 3.8877572537736302
57 | }
58 | }
59 | },
60 | {
61 | "ew": {
62 | "wpa": {
63 | "Left": 0
64 | }
65 | }
66 | },
67 | {
68 | "ew": {
69 | "wpa": {
70 | "Right": -11.018936377199028
71 | }
72 | }
73 | }
74 | ]
75 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/HalfWrapped/HalfWrapped.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 8960212111377330785,
3 | "samples": [
4 | {
5 | "hw": {
6 | "wpa": {
7 | "Left": 3
8 | }
9 | }
10 | },
11 | {
12 | "hw": {
13 | "wpa": {
14 | "Right": -30
15 | }
16 | }
17 | },
18 | {
19 | "hw": {
20 | "wpa": {
21 | "Right": -16
22 | }
23 | }
24 | },
25 | {
26 | "hw": {
27 | "wpa": {
28 | "Right": 27
29 | }
30 | }
31 | },
32 | {
33 | "hw": {
34 | "wpa": {
35 | "Right": 28
36 | }
37 | }
38 | },
39 | {
40 | "hw": {
41 | "wpa": {
42 | "Left": 5
43 | }
44 | }
45 | },
46 | {
47 | "hw": {
48 | "wpa": {
49 | "Right": 29
50 | }
51 | }
52 | },
53 | {
54 | "hw": {
55 | "wpa": {
56 | "Left": -15
57 | }
58 | }
59 | },
60 | {
61 | "hw": {
62 | "wpa": {
63 | "Left": -22
64 | }
65 | }
66 | },
67 | {
68 | "hw": {
69 | "wpa": {
70 | "Left": -15
71 | }
72 | }
73 | }
74 | ]
75 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/InnerBox/InnerBox.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -7851554943605849957,
3 | "samples": [
4 | {
5 | "ibA": 2,
6 | "ibS": "?O$KjxT`#8\u0011\u001fxl?$UC2램;.b)4i\tG",
7 | "ibX": 7
8 | },
9 | {
10 | "ibA": 15,
11 | "ibS": "Q\"#𠕐~, ftx",
12 | "ibX": -2
13 | },
14 | {
15 | "ibA": 25,
16 | "ibS": "L",
17 | "ibX": -15
18 | },
19 | {
20 | "ibA": 25,
21 | "ibS": "\ta𥲁t3q`{\u0001\u000c\u001aZ)c6\u0002/dj",
47 | "ibX": -10
48 | },
49 | {
50 | "ibA": {
51 | "created": "1864-05-14T00:00:01.011Z",
52 | "name": "\u0007}5;7i\u000by\u0006$HU3fK\u0008\u001a}26]",
53 | "id": -2
54 | },
55 | "ibS": "^2C5",
56 | "ibX": -8
57 | },
58 | {
59 | "ibA": {
60 | "created": "1864-06-08T00:00:01.011Z",
61 | "name": "T",
62 | "id": -15
63 | },
64 | "ibS": "x\u001bゼ6;\u001fwo44N",
65 | "ibX": -1
66 | },
67 | {
68 | "ibA": {
69 | "created": "1864-05-29T00:00:01.011Z",
70 | "name": null,
71 | "id": 19
72 | },
73 | "ibS": "\u000f\u0000\rB9",
74 | "ibX": 29
75 | },
76 | {
77 | "ibA": {
78 | "created": "1864-05-20T00:00:01.011Z",
79 | "name": null,
80 | "id": 13
81 | },
82 | "ibS": "Ci1qpG=;M\u0016q^5a\u0003\u0001\u0010𡹾",
83 | "ibX": -9
84 | },
85 | {
86 | "ibA": {
87 | "created": "1864-06-01T00:00:01.011Z",
88 | "name": "\u0003\u0019\r![\u0003ceJI]AU",
89 | "id": -30
90 | },
91 | "ibS": "\u0012G_\u000e>\u001b\u0010t%違{D\u001ffXl\u0014\u001e(S\u000bd\u0010",
92 | "ibX": 6
93 | }
94 | ]
95 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/PartiallyWrapped/PartiallyWrapped.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -797789241917621471,
3 | "samples": [
4 | {
5 | "pw": {
6 | "wpa": {
7 | "Left": -30
8 | }
9 | }
10 | },
11 | {
12 | "pw": {
13 | "wpa": {
14 | "Left": 27
15 | }
16 | }
17 | },
18 | {
19 | "pw": {
20 | "wpa": {
21 | "Left": -1
22 | }
23 | }
24 | },
25 | {
26 | "pw": {
27 | "wpa": {
28 | "Left": 8
29 | }
30 | }
31 | },
32 | {
33 | "pw": {
34 | "wpa": {
35 | "Left": -17
36 | }
37 | }
38 | },
39 | {
40 | "pw": {
41 | "wpa": {
42 | "Left": 19
43 | }
44 | }
45 | },
46 | {
47 | "pw": {
48 | "wpa": {
49 | "Left": 28
50 | }
51 | }
52 | },
53 | {
54 | "pw": {
55 | "wpa": {
56 | "Left": -14
57 | }
58 | }
59 | },
60 | {
61 | "pw": {
62 | "wpa": {
63 | "Left": 7
64 | }
65 | }
66 | },
67 | {
68 | "pw": {
69 | "wpa": {
70 | "Left": 20
71 | }
72 | }
73 | }
74 | ]
75 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/Person/Person.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 6820255037867830086,
3 | "samples": [
4 | {
5 | "created": "1864-04-11T00:00:01.011Z",
6 | "name": " \u0007~2GY\u000f$s\u0002@\u0017z\u0002\u000e\t",
7 | "id": -22
8 | },
9 | {
10 | "created": "1864-04-25T00:00:01.011Z",
11 | "name": null,
12 | "id": 11
13 | },
14 | {
15 | "created": "1864-04-12T00:00:01.011Z",
16 | "name": "{K2^X\u0005'G4𫡛1",
17 | "id": 12
18 | },
19 | {
20 | "created": "1864-04-10T00:00:01.011Z",
21 | "name": null,
22 | "id": -1
23 | },
24 | {
25 | "created": "1864-04-26T00:00:01.011Z",
26 | "name": "\u0001",
27 | "id": 24
28 | },
29 | {
30 | "created": "1864-05-29T00:00:01.011Z",
31 | "name": "$Y\u000f,u\u001dm\u0005J/\u0000\u0008}",
32 | "id": 28
33 | },
34 | {
35 | "created": "1864-06-03T00:00:01.011Z",
36 | "name": "kjMa䅹nyLB}\u000c-w\u0010I_\n𭉵\u0010*.",
37 | "id": 0
38 | },
39 | {
40 | "created": "1864-04-24T00:00:01.011Z",
41 | "name": null,
42 | "id": -26
43 | },
44 | {
45 | "created": "1864-04-28T00:00:01.011Z",
46 | "name": "rED-X@0PcqUom\u0011a\u0002𑅨Y+",
47 | "id": -10
48 | },
49 | {
50 | "created": "1864-05-22T00:00:01.011Z",
51 | "name": null,
52 | "id": 24
53 | }
54 | ]
55 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/ScrambledTypeParameterRefs/ScrambledTypeParameterRefs.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 3711347212009762416,
3 | "samples": [
4 | {
5 | "stprb": 10,
6 | "stpre": -10,
7 | "stprd": -1,
8 | "stpra": 22,
9 | "stprf": 9,
10 | "stprc": 29
11 | },
12 | {
13 | "stprb": -8,
14 | "stpre": -9,
15 | "stprd": -4,
16 | "stpra": 29,
17 | "stprf": 15,
18 | "stprc": 1
19 | },
20 | {
21 | "stprb": -21,
22 | "stpre": -7,
23 | "stprd": 25,
24 | "stpra": 25,
25 | "stprf": 29,
26 | "stprc": -15
27 | },
28 | {
29 | "stprb": 2,
30 | "stpre": -1,
31 | "stprd": 14,
32 | "stpra": -6,
33 | "stprf": -30,
34 | "stprc": -26
35 | },
36 | {
37 | "stprb": 20,
38 | "stpre": 4,
39 | "stprd": -20,
40 | "stpra": 26,
41 | "stprf": 8,
42 | "stprc": -27
43 | },
44 | {
45 | "stprb": 26,
46 | "stpre": 9,
47 | "stprd": -23,
48 | "stpra": 10,
49 | "stprf": 11,
50 | "stprc": -4
51 | },
52 | {
53 | "stprb": 4,
54 | "stpre": -12,
55 | "stprd": -20,
56 | "stpra": 6,
57 | "stprf": 10,
58 | "stprc": -16
59 | },
60 | {
61 | "stprb": -25,
62 | "stpre": 14,
63 | "stprd": -2,
64 | "stpra": 29,
65 | "stprf": 25,
66 | "stprc": 24
67 | },
68 | {
69 | "stprb": 17,
70 | "stpre": 23,
71 | "stprd": 6,
72 | "stpra": -18,
73 | "stprf": -13,
74 | "stprc": -20
75 | },
76 | {
77 | "stprb": 22,
78 | "stpre": 28,
79 | "stprd": -2,
80 | "stpra": -18,
81 | "stprf": -15,
82 | "stprc": -29
83 | }
84 | ]
85 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/SecondLayer/SecondLayer.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -23528167967323917,
3 | "samples": [
4 | {
5 | "sl": {
6 | "wp2a": 22,
7 | "wp2b": -18
8 | },
9 | "zed": "DtQÜ\u0005ß\u0003GS=e\u001e\u001c8ø\u0008\u000c]3\u000f«P\u000eSþòCî"
10 | },
11 | {
12 | "sl": {
13 | "wp2a": 18,
14 | "wp2b": -22
15 | },
16 | "zed": "{oh.\u0011gJÓzÔã<\u0013?lUwòà×\u0001û"
17 | },
18 | {
19 | "sl": {
20 | "wp2a": -30,
21 | "wp2b": -24
22 | },
23 | "zed": "¹[\u0004lkBý\u0018r¹"
24 | },
25 | {
26 | "sl": {
27 | "wp2a": -8,
28 | "wp2b": -27
29 | },
30 | "zed": "/@\u0000D5ARæR7\u0013\u0004\u0019\u0007\u000fÓÚq\u0010i\u001di"
31 | },
32 | {
33 | "sl": {
34 | "wp2a": 28,
35 | "wp2b": -20
36 | },
37 | "zed": "9+\u000e_K$,OJÌgh\u00198Ì/\u0015a9Ò» x£\u00189\u0014r"
38 | },
39 | {
40 | "sl": {
41 | "wp2a": 17,
42 | "wp2b": 27
43 | },
44 | "zed": "\u0016>ùÓAv31}'.{!:Wd\u0005-§V\u0006\u0018É"
45 | },
46 | {
47 | "sl": {
48 | "wp2a": 10,
49 | "wp2b": 16
50 | },
51 | "zed": "'Õ~E4"
52 | },
53 | {
54 | "sl": {
55 | "wp2a": 18,
56 | "wp2b": 26
57 | },
58 | "zed": "vZnÄ|T\u0019Ó\u0019\u0017kÅ*Ê\u0011Ö¼4&z2Î"
59 | },
60 | {
61 | "sl": {
62 | "wp2a": -16,
63 | "wp2b": 11
64 | },
65 | "zed": "G¿¤B\u0006º'\u001fÁ|;k\u000eU\u000e5"
66 | },
67 | {
68 | "sl": {
69 | "wp2a": 10,
70 | "wp2b": -13
71 | },
72 | "zed": "P\u00030p3\u0001Z\u0010^b;r$\u0016'ßJp\u001a"
73 | }
74 | ]
75 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/Simple/Simple.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 1801824973039036285,
3 | "samples": [
4 | {
5 | "sa": 4,
6 | "sb": "6\u0019Y\u001e[t'=u\u0017^a,p"
37 | }
38 | },
39 | {
40 | "choice": {
41 | "Right": 12
42 | }
43 | },
44 | {
45 | "choice": {
46 | "Left": ",|B`][e\n@n1[\rh\u0010\u0007"
47 | }
48 | },
49 | {
50 | "choice": {
51 | "Left": "W^\u001c]𓋷)Uh\u0013+",
90 | -19.195050150777067
91 | ]
92 | }
93 | }
94 | ]
95 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/TwoTypeParameters/TwoTypeParameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 1476930007050195571,
3 | "samples": [
4 | {
5 | "ttpFirst": 14,
6 | "ttpSecond": -24,
7 | "ttpId": 10,
8 | "ttpThird": [
9 | 25,
10 | 20
11 | ]
12 | },
13 | {
14 | "ttpFirst": 3,
15 | "ttpSecond": 9,
16 | "ttpId": -12,
17 | "ttpThird": [
18 | -23,
19 | 20
20 | ]
21 | },
22 | {
23 | "ttpFirst": 6,
24 | "ttpSecond": -26,
25 | "ttpId": -14,
26 | "ttpThird": [
27 | 19,
28 | -20
29 | ]
30 | },
31 | {
32 | "ttpFirst": 3,
33 | "ttpSecond": -20,
34 | "ttpId": -28,
35 | "ttpThird": [
36 | -22,
37 | -15
38 | ]
39 | },
40 | {
41 | "ttpFirst": 9,
42 | "ttpSecond": 22,
43 | "ttpId": 1,
44 | "ttpThird": [
45 | -1,
46 | 18
47 | ]
48 | },
49 | {
50 | "ttpFirst": -18,
51 | "ttpSecond": -24,
52 | "ttpId": 10,
53 | "ttpThird": [
54 | -10,
55 | -3
56 | ]
57 | },
58 | {
59 | "ttpFirst": -4,
60 | "ttpSecond": 20,
61 | "ttpId": 3,
62 | "ttpThird": [
63 | -12,
64 | 17
65 | ]
66 | },
67 | {
68 | "ttpFirst": 13,
69 | "ttpSecond": -15,
70 | "ttpId": -29,
71 | "ttpThird": [
72 | 21,
73 | -30
74 | ]
75 | },
76 | {
77 | "ttpFirst": -16,
78 | "ttpSecond": -17,
79 | "ttpId": 2,
80 | "ttpThird": [
81 | 6,
82 | -28
83 | ]
84 | },
85 | {
86 | "ttpFirst": 29,
87 | "ttpSecond": -23,
88 | "ttpId": -18,
89 | "ttpThird": [
90 | 26,
91 | 21
92 | ]
93 | }
94 | ]
95 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/UnnamedProduct/UnnamedProduct.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 5356500220752652327,
3 | "samples": [
4 | [
5 | "\\`p\\\u0008\u000c",
6 | -19
7 | ],
8 | [
9 | "𑀀",
10 | -20
11 | ],
12 | [
13 | "`>\t6SG5U𗹾Y𰾳1d\u0016\u001a\u0013zj\u0014\u000b\u001bU",
14 | -12
15 | ],
16 | [
17 | "\u0010N'\u0010@.\u001d2<\u0014$)1LtT\u0006$",
18 | -6
19 | ],
20 | [
21 | "Lv",
22 | 3
23 | ],
24 | [
25 | "2Q\u0010\u001d=+\u0005\u001c1\u000b3\u0019\u0016\u0003C\u001b*NE_",
26 | -1
27 | ],
28 | [
29 | "teCg2巊\u00050",
30 | -26
31 | ],
32 | [
33 | "\u001eVP{\u0006D뮰+J⨢\u0008",
34 | -23
35 | ],
36 | [
37 | ";/i",
38 | -22
39 | ],
40 | [
41 | "n<p{Q*BE[\u00148\u0004>\nZ",
42 | -5
43 | ]
44 | ]
45 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/User/User.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 4516830748937394304,
3 | "samples": [
4 | {
5 | "userIdent": "DbS",
6 | "userPassword": null,
7 | "userTimezone": "^\u0015\u000f,\u0017"
8 | },
9 | {
10 | "userIdent": "N\u0001O",
11 | "userPassword": null,
12 | "userTimezone": "kz=\u0012[\u001b_r\u0016x\u001e"
13 | },
14 | {
15 | "userIdent": "]M",
16 | "userPassword": "\u0019\u000c\u0018-\"\"O\u000eV𬝻cD\u001d\u0006C\u0003~{-",
17 | "userTimezone": "S𠽯H\u0015X"
18 | },
19 | {
20 | "userIdent": ",\u001f&R<\u0011\u0008",
21 | "userPassword": null,
22 | "userTimezone": "/𲄷G\u0011Y$-z^\u0008埵\u000b\u0008}\u0006O{w\u001f-"
23 | },
24 | {
25 | "userIdent": "Qbd3⏡px^z[291=𫱙o淓}",
26 | "userPassword": null,
27 | "userTimezone": ""
28 | },
29 | {
30 | "userIdent": "",
31 | "userPassword": "l\u0002]\u0003u\u0013v\t&%\t7",
32 | "userTimezone": "'62(JnFB"
33 | },
34 | {
35 | "userIdent": "z/u\u0012tRG\u001dP=xS\u001e𨒍=H\u000c\u001a",
36 | "userPassword": "x,D\u001a\u001d^\u001dJj\"M(\u000b&UbHB\u0019",
37 | "userTimezone": "M\u000e${7HxZ8\u0006c%Ap"
38 | },
39 | {
40 | "userIdent": "\u0017H\u0011nrK",
41 | "userPassword": null,
42 | "userTimezone": "𧳏r,'FX"
43 | },
44 | {
45 | "userIdent": "\u001d徹\u0000B7r]R,\u001ea{d\u0011\u001a\u0012\u001d",
46 | "userPassword": "𗔮\u0018\u0016/F0",
47 | "userTimezone": "ZN\u001cwZEP\u000ek75v??\u00141 &;"
48 | },
49 | {
50 | "userIdent": "\u0013\rPR1.\u0019J8",
51 | "userPassword": "+ꤻ\u0017Q@\u00040U5\u000bc\\/vd\\\u001a#",
52 | "userTimezone": "X!rFBx"
53 | }
54 | ]
55 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/UserId/UserId.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -9154406842179955350,
3 | "samples": [
4 | 28,
5 | 30,
6 | -26,
7 | -3,
8 | 8,
9 | 19,
10 | 21,
11 | 30,
12 | 6,
13 | -2
14 | ]
15 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/WrapThree/WrapThree.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -497434135695006380,
3 | "samples": [
4 | {
5 | "wp2a": 24,
6 | "wp2cb": [
7 | 0,
8 | 0
9 | ],
10 | "wp2ab": [
11 | -3,
12 | -22
13 | ],
14 | "wp2b": 15
15 | },
16 | {
17 | "wp2a": -28,
18 | "wp2cb": [
19 | 25,
20 | -14
21 | ],
22 | "wp2ab": [
23 | 16,
24 | -11
25 | ],
26 | "wp2b": 8
27 | },
28 | {
29 | "wp2a": -18,
30 | "wp2cb": [
31 | -2,
32 | 13
33 | ],
34 | "wp2ab": [
35 | -1,
36 | -4
37 | ],
38 | "wp2b": 0
39 | },
40 | {
41 | "wp2a": -29,
42 | "wp2cb": [
43 | 20,
44 | 11
45 | ],
46 | "wp2ab": [
47 | -14,
48 | -30
49 | ],
50 | "wp2b": 26
51 | },
52 | {
53 | "wp2a": 28,
54 | "wp2cb": [
55 | 1,
56 | 22
57 | ],
58 | "wp2ab": [
59 | 19,
60 | 21
61 | ],
62 | "wp2b": 28
63 | },
64 | {
65 | "wp2a": 1,
66 | "wp2cb": [
67 | 25,
68 | -27
69 | ],
70 | "wp2ab": [
71 | -28,
72 | -28
73 | ],
74 | "wp2b": -4
75 | },
76 | {
77 | "wp2a": 14,
78 | "wp2cb": [
79 | -22,
80 | -8
81 | ],
82 | "wp2ab": [
83 | 23,
84 | -24
85 | ],
86 | "wp2b": -3
87 | },
88 | {
89 | "wp2a": 13,
90 | "wp2cb": [
91 | -15,
92 | 26
93 | ],
94 | "wp2ab": [
95 | 20,
96 | 6
97 | ],
98 | "wp2b": 16
99 | },
100 | {
101 | "wp2a": -27,
102 | "wp2cb": [
103 | 2,
104 | 10
105 | ],
106 | "wp2ab": [
107 | -17,
108 | -1
109 | ],
110 | "wp2b": -29
111 | },
112 | {
113 | "wp2a": -26,
114 | "wp2cb": [
115 | -9,
116 | -28
117 | ],
118 | "wp2ab": [
119 | 12,
120 | 12
121 | ],
122 | "wp2b": -30
123 | }
124 | ]
125 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/WrappedWrapper/WrappedWrapper.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -4541499265744098089,
3 | "samples": [
4 | {
5 | "ww": {
6 | "wpa": null
7 | }
8 | },
9 | {
10 | "ww": {
11 | "wpa": 28
12 | }
13 | },
14 | {
15 | "ww": {
16 | "wpa": null
17 | }
18 | },
19 | {
20 | "ww": null
21 | },
22 | {
23 | "ww": {
24 | "wpa": 3
25 | }
26 | },
27 | {
28 | "ww": {
29 | "wpa": 17
30 | }
31 | },
32 | {
33 | "ww": {
34 | "wpa": -5
35 | }
36 | },
37 | {
38 | "ww": {
39 | "wpa": 29
40 | }
41 | },
42 | {
43 | "ww": {
44 | "wpa": -29
45 | }
46 | },
47 | {
48 | "ww": null
49 | }
50 | ]
51 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/Wrapper/Wrapper.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -8767615348653689682,
3 | "samples": [
4 | {
5 | "wpa": 10
6 | },
7 | {
8 | "wpa": -8
9 | },
10 | {
11 | "wpa": -15
12 | },
13 | {
14 | "wpa": 3
15 | },
16 | {
17 | "wpa": -17
18 | },
19 | {
20 | "wpa": 13
21 | },
22 | {
23 | "wpa": 0
24 | },
25 | {
26 | "wpa": 15
27 | },
28 | {
29 | "wpa": -6
30 | },
31 | {
32 | "wpa": -21
33 | }
34 | ]
35 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/product/Wrapper2/Wrapper2.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -3206408502528725740,
3 | "samples": [
4 | {
5 | "wp2a": 17,
6 | "wp2b": 15
7 | },
8 | {
9 | "wp2a": 1,
10 | "wp2b": -6
11 | },
12 | {
13 | "wp2a": 27,
14 | "wp2b": 28
15 | },
16 | {
17 | "wp2a": -1,
18 | "wp2b": 16
19 | },
20 | {
21 | "wp2a": 9,
22 | "wp2b": -27
23 | },
24 | {
25 | "wp2a": -27,
26 | "wp2b": 12
27 | },
28 | {
29 | "wp2a": -27,
30 | "wp2b": 5
31 | },
32 | {
33 | "wp2a": -14,
34 | "wp2b": -11
35 | },
36 | {
37 | "wp2a": 19,
38 | "wp2b": 13
39 | },
40 | {
41 | "wp2a": 19,
42 | "wp2b": -17
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/subs/A/A.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 6325633533011437127,
3 | "samples": [
4 | -24,
5 | 16,
6 | 8,
7 | 2,
8 | -17,
9 | -17,
10 | 18,
11 | 19,
12 | -9,
13 | 19
14 | ]
15 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/subs/B/B.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -2094573881888746220,
3 | "samples": [
4 | [
5 | "*&5{\rë:W\u001d",
6 | -30
7 | ],
8 | [
9 | "v\u0004\u001b\u0011I\u0010\u0012\u0017\u001d#d\u0004/¼\u0002Ól\u0018y¼\u001cxy5",
10 | 5
11 | ],
12 | [
13 | "\u00189\u0012\u0011Z\u000eaü¢\u000e+:MSÔÞ\u001f?\\SuI",
14 | 2
15 | ],
16 | [
17 | "ül=+t\u000f/q<2,BZ\u001f¤x^Vbn\u001dr\u001d\t\u001d",
18 | 1
19 | ],
20 | [
21 | "@\u001c\u0013\u000cÙ!C",
22 | 7
23 | ],
24 | [
25 | "'.®",
26 | 5
27 | ],
28 | [
29 | "°J\u0004!C´Oi_J[\u0004",
30 | -16
31 | ],
32 | [
33 | "pD\u0000tirW^\u00014\u001bO"
27 | },
28 | {
29 | "tag": "Name",
30 | "contents": "W\u0000\u0013k("
31 | },
32 | {
33 | "tag": "Name",
34 | "contents": "LAQ@g<|^\u0006!n(C"
35 | },
36 | {
37 | "tag": "Name",
38 | "contents": "0\u000b6&)YBX\u00142\u00116=C-\u0004\u0001:\u001frw"
39 | },
40 | {
41 | "tag": "Name",
42 | "contents": ""
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/NewType/NewType.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -7933038495455321262,
3 | "samples": [
4 | -30,
5 | -30,
6 | -7,
7 | -5,
8 | 30,
9 | -14,
10 | 26,
11 | -25,
12 | -12,
13 | 25
14 | ]
15 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/OnOrOff/Off.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 3228432956609522149,
3 | "samples": [
4 | "Off",
5 | "Off",
6 | "Off",
7 | "Off",
8 | "Off",
9 | "Off",
10 | "Off",
11 | "Off",
12 | "Off",
13 | "Off"
14 | ]
15 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/OnOrOff/On.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 2014006095097997093,
3 | "samples": [
4 | "On",
5 | "On",
6 | "On",
7 | "On",
8 | "On",
9 | "On",
10 | "On",
11 | "On",
12 | "On",
13 | "On"
14 | ]
15 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/Result/Error.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 6838542643758342093,
3 | "samples": [
4 | {
5 | "tag": "Error",
6 | "contents": -15
7 | },
8 | {
9 | "tag": "Error",
10 | "contents": -5
11 | },
12 | {
13 | "tag": "Error",
14 | "contents": -14
15 | },
16 | {
17 | "tag": "Error",
18 | "contents": -11
19 | },
20 | {
21 | "tag": "Error",
22 | "contents": -2
23 | },
24 | {
25 | "tag": "Error",
26 | "contents": 15
27 | },
28 | {
29 | "tag": "Error",
30 | "contents": 12
31 | },
32 | {
33 | "tag": "Error",
34 | "contents": 21
35 | },
36 | {
37 | "tag": "Error",
38 | "contents": -10
39 | },
40 | {
41 | "tag": "Error",
42 | "contents": -18
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/Result/Success.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -2235679539073054709,
3 | "samples": [
4 | {
5 | "tag": "Success",
6 | "contents": 17
7 | },
8 | {
9 | "tag": "Success",
10 | "contents": 20
11 | },
12 | {
13 | "tag": "Success",
14 | "contents": 3
15 | },
16 | {
17 | "tag": "Success",
18 | "contents": -6
19 | },
20 | {
21 | "tag": "Success",
22 | "contents": 15
23 | },
24 | {
25 | "tag": "Success",
26 | "contents": -14
27 | },
28 | {
29 | "tag": "Success",
30 | "contents": -26
31 | },
32 | {
33 | "tag": "Success",
34 | "contents": -7
35 | },
36 | {
37 | "tag": "Success",
38 | "contents": -27
39 | },
40 | {
41 | "tag": "Success",
42 | "contents": 21
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/SingleSum/SingleSum.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 5368290304339618907,
3 | "samples": [
4 | [],
5 | [],
6 | [],
7 | [],
8 | [],
9 | [],
10 | [],
11 | [],
12 | [],
13 | []
14 | ]
15 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/SumVariant/HasMixed.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -7061981691673967949,
3 | "samples": [
4 | {
5 | "tag": "HasMixed",
6 | "contents": [
7 | -15,
8 | "@-:g(*EL^A5c\u0005o𢭍\u001f4:",
9 | -17.240536744287486
10 | ]
11 | },
12 | {
13 | "tag": "HasMixed",
14 | "contents": [
15 | 21,
16 | "x\u0018(眛h899\u000bjg\u0014Vs|X;",
17 | -42.43297806958867
18 | ]
19 | },
20 | {
21 | "tag": "HasMixed",
22 | "contents": [
23 | -28,
24 | "_bF(𝥕\u0018$",
25 | 31.935440317553308
26 | ]
27 | },
28 | {
29 | "tag": "HasMixed",
30 | "contents": [
31 | -20,
32 | "jp3",
33 | -10.280395262412918
34 | ]
35 | },
36 | {
37 | "tag": "HasMixed",
38 | "contents": [
39 | 2,
40 | "\"}1@^V𥐦[\u00016IT9\nX𲉢\u001e:\u0000:W",
41 | -143.11809448070778
42 | ]
43 | },
44 | {
45 | "tag": "HasMixed",
46 | "contents": [
47 | 17,
48 | "\u0007}g4\u0005YO",
49 | -101.61797903510524
50 | ]
51 | },
52 | {
53 | "tag": "HasMixed",
54 | "contents": [
55 | -29,
56 | "𭌇\u0008FT74ZR\u0004d4q(s~G3𐘧",
57 | -47.18039748830254
58 | ]
59 | },
60 | {
61 | "tag": "HasMixed",
62 | "contents": [
63 | -23,
64 | "\u001a[Lt",
65 | -21.637548733423014
66 | ]
67 | },
68 | {
69 | "tag": "HasMixed",
70 | "contents": [
71 | 17,
72 | "S.e",
73 | -318.47993406783405
74 | ]
75 | },
76 | {
77 | "tag": "HasMixed",
78 | "contents": [
79 | -19,
80 | "\u0017e$Wb\u001f\u000c\u000f\u0008xN/𥢗梆8\u0006<\u0015mV$\u001f$\u000en",
81 | -5.220294304336202
82 | ]
83 | }
84 | ]
85 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/SumVariant/HasMultipleInts.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 3274979294768835177,
3 | "samples": [
4 | {
5 | "tag": "HasMultipleInts",
6 | "contents": [
7 | -24,
8 | 5
9 | ]
10 | },
11 | {
12 | "tag": "HasMultipleInts",
13 | "contents": [
14 | 5,
15 | 12
16 | ]
17 | },
18 | {
19 | "tag": "HasMultipleInts",
20 | "contents": [
21 | 26,
22 | 21
23 | ]
24 | },
25 | {
26 | "tag": "HasMultipleInts",
27 | "contents": [
28 | -12,
29 | -25
30 | ]
31 | },
32 | {
33 | "tag": "HasMultipleInts",
34 | "contents": [
35 | 8,
36 | -21
37 | ]
38 | },
39 | {
40 | "tag": "HasMultipleInts",
41 | "contents": [
42 | 16,
43 | 8
44 | ]
45 | },
46 | {
47 | "tag": "HasMultipleInts",
48 | "contents": [
49 | -28,
50 | -24
51 | ]
52 | },
53 | {
54 | "tag": "HasMultipleInts",
55 | "contents": [
56 | 29,
57 | 19
58 | ]
59 | },
60 | {
61 | "tag": "HasMultipleInts",
62 | "contents": [
63 | 19,
64 | 8
65 | ]
66 | },
67 | {
68 | "tag": "HasMultipleInts",
69 | "contents": [
70 | 0,
71 | 24
72 | ]
73 | }
74 | ]
75 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/SumVariant/HasNameOrIdNumber.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": -1135875169984086649,
3 | "samples": [
4 | {
5 | "tag": "HasNameOrIdNumber",
6 | "contents": [
7 | {
8 | "tag": "Name",
9 | "contents": "\n\u0008VPr&A\u000c!N\u0010q\u0015%",
27 | "b3": 16
28 | },
29 | {
30 | "tag": "B2",
31 | "b2": "ez\u001619=4Q,aNDz𢤏7kE&4WE\u000f>b'",
32 | "b3": -19
33 | },
34 | {
35 | "tag": "B2",
36 | "b2": "K\rd)\u0005\u001ca4]-q3zgI<\u001bU𢤁\\C鄸",
37 | "b3": 23
38 | },
39 | {
40 | "tag": "B2",
41 | "b2": "",
42 | "b3": -29
43 | },
44 | {
45 | "tag": "B2",
46 | "b2": "x\u0010\r%n'Q,",
47 | "b3": 7
48 | },
49 | {
50 | "tag": "B2",
51 | "b2": "+=",
52 | "b3": -18
53 | }
54 | ]
55 | }
--------------------------------------------------------------------------------
/test/interface/golden/golden/sum/WithTuple/WithTuple.json:
--------------------------------------------------------------------------------
1 | {
2 | "seed": 3731922109012887365,
3 | "samples": [
4 | [
5 | 17,
6 | -23
7 | ],
8 | [
9 | 5,
10 | -3
11 | ],
12 | [
13 | 16,
14 | 0
15 | ],
16 | [
17 | -11,
18 | 1
19 | ],
20 | [
21 | -17,
22 | 26
23 | ],
24 | [
25 | 17,
26 | 16
27 | ],
28 | [
29 | -1,
30 | 12
31 | ],
32 | [
33 | 1,
34 | -3
35 | ],
36 | [
37 | 10,
38 | -23
39 | ],
40 | [
41 | 8,
42 | -28
43 | ]
44 | ]
45 | }
--------------------------------------------------------------------------------
/test/interface/golden/options/NameOrIdNumber.ml:
--------------------------------------------------------------------------------
1 | type nameOrIdNumber =
2 | | Name of string
3 | | IdNumber of int
4 |
5 | let encodeNameOrIdNumber x =
6 | match x with
7 | | Name y0 ->
8 | Aeson.Encode.object_
9 | [ ( "tag", Aeson.Encode.string "name" )
10 | ; ( "contents", Aeson.Encode.string y0 )
11 | ]
12 | | IdNumber y0 ->
13 | Aeson.Encode.object_
14 | [ ( "tag", Aeson.Encode.string "idnumber" )
15 | ; ( "contents", Aeson.Encode.int y0 )
16 | ]
17 |
18 | let decodeNameOrIdNumber json =
19 | match Aeson.Decode.(field "tag" string json) with
20 | | "name" ->
21 | (match Aeson.Decode.(field "contents" string json) with
22 | | v -> Js_result.Ok (Name v)
23 | | exception Aeson.Decode.DecodeError message -> Js_result.Error ("name: " ^ message)
24 | )
25 | | "idnumber" ->
26 | (match Aeson.Decode.(field "contents" int json) with
27 | | v -> Js_result.Ok (IdNumber v)
28 | | exception Aeson.Decode.DecodeError message -> Js_result.Error ("idnumber: " ^ message)
29 | )
30 | | err -> Js_result.Error ("Unknown tag value found '" ^ err ^ "'.")
31 | | exception Aeson.Decode.DecodeError message -> Js_result.Error message
32 |
--------------------------------------------------------------------------------
/test/interface/golden/options/NameOrIdNumber.mli:
--------------------------------------------------------------------------------
1 | type nameOrIdNumber =
2 | | Name of string
3 | | IdNumber of int
4 |
5 | val encodeNameOrIdNumber : nameOrIdNumber -> Js_json.t
6 |
7 | val decodeNameOrIdNumber : Js_json.t -> (nameOrIdNumber, string) Js_result.t
8 |
--------------------------------------------------------------------------------
/test/interface/golden/options/Person.ml:
--------------------------------------------------------------------------------
1 | type person =
2 | { id : int
3 | ; name : (string) option
4 | ; created : Js_date.t
5 | }
6 |
7 | let encodePerson x =
8 | Aeson.Encode.object_
9 | [ ( "ID", Aeson.Encode.int x.id )
10 | ; ( "NAME", Aeson.Encode.optional Aeson.Encode.string x.name )
11 | ; ( "CREATED", Aeson.Encode.date x.created )
12 | ]
13 |
14 | let decodePerson json =
15 | match Aeson.Decode.
16 | { id = field "ID" int json
17 | ; name = optional (field "NAME" string) json
18 | ; created = field "CREATED" date json
19 | }
20 | with
21 | | v -> Js_result.Ok v
22 | | exception Aeson.Decode.DecodeError message -> Js_result.Error ("decodePerson: " ^ message)
23 |
--------------------------------------------------------------------------------
/test/interface/golden/options/Person.mli:
--------------------------------------------------------------------------------
1 | type person =
2 | { id : int
3 | ; name : (string) option
4 | ; created : Js_date.t
5 | }
6 |
7 | val encodePerson : person -> Js_json.t
8 |
9 | val decodePerson : Js_json.t -> (person, string) Js_result.t
10 |
--------------------------------------------------------------------------------
/test/interface/golden/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ocaml-export-spec",
3 | "private": true,
4 | "version": "0.0.0",
5 | "description": "",
6 | "main": "index.js",
7 | "scripts": {
8 | "build": "bsb -make-world",
9 | "start": "bsb -make-world -w",
10 | "clean": "bsb -clean-world",
11 | "test": "npm run build && jest"
12 | },
13 | "keywords": [],
14 | "author": "",
15 | "license": "MIT",
16 | "dependencies": {
17 | "bs-aeson": "^3.0.0"
18 | },
19 | "devDependencies": {
20 | "bs-aeson-spec": "^2.0.0",
21 | "bs-platform": "^3.1.5",
22 | "@glennsl/bs-jest": "^0.4.2",
23 | "bs-node": "github:buckletypes/bs-node"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/test/interface/golden/person.json:
--------------------------------------------------------------------------------
1 | {"id" : 0, "name" : "James", "created" : "2017-11-07T04:05:09.518Z"}
2 |
--------------------------------------------------------------------------------
/test/interface/golden/product/Box.mli:
--------------------------------------------------------------------------------
1 | type 'a0 innerBox =
2 | { ibA : 'a0
3 | ; ibS : string
4 | ; ibX : int
5 | }
6 |
7 | val encodeInnerBox : ('a0 -> Js_json.t) -> 'a0 innerBox -> Js_json.t
8 |
9 | val decodeInnerBox : (Js_json.t -> ('a0, string) Belt.Result.t) -> Js_json.t -> ('a0 innerBox, string) Belt.Result.t
10 |
11 | type outerBox =
12 | | OuterBox of (Person.person) innerBox
13 |
14 | val encodeOuterBox : outerBox -> Js_json.t
15 |
16 | val decodeOuterBox : Js_json.t -> (outerBox, string) Belt.Result.t
17 |
18 | type auditAction =
19 | | Create
20 | | Delete
21 | | Update
22 |
23 | val encodeAuditAction : auditAction -> Js_json.t
24 |
25 | val decodeAuditAction : Js_json.t -> (auditAction, string) Belt.Result.t
26 |
27 | type 'a0 auditModel =
28 | { auditModel : 'a0
29 | ; originalId : string
30 | ; auditAction : auditAction
31 | ; editedBy : string
32 | ; editedOn : string
33 | }
34 |
35 | val encodeAuditModel : ('a0 -> Js_json.t) -> 'a0 auditModel -> Js_json.t
36 |
37 | val decodeAuditModel : (Js_json.t -> ('a0, string) Belt.Result.t) -> Js_json.t -> ('a0 auditModel, string) Belt.Result.t
38 |
39 | type user =
40 | { userIdent : string
41 | ; userPassword : (string) option
42 | ; userTimezone : string
43 | }
44 |
45 | val encodeUser : user -> Js_json.t
46 |
47 | val decodeUser : Js_json.t -> (user, string) Belt.Result.t
48 |
49 | type userAudit =
50 | | UserAudit of (user) auditModel
51 |
52 | val encodeUserAudit : userAudit -> Js_json.t
53 |
54 | val decodeUserAudit : Js_json.t -> (userAudit, string) Belt.Result.t
55 |
--------------------------------------------------------------------------------
/test/interface/golden/product/Card.ml:
--------------------------------------------------------------------------------
1 | type suit =
2 | | Clubs
3 | | Diamonds
4 | | Hearts
5 | | Spades
6 |
7 | let encodeSuit x =
8 | match x with
9 | | Clubs ->
10 | Aeson.Encode.string "Clubs"
11 | | Diamonds ->
12 | Aeson.Encode.string "Diamonds"
13 | | Hearts ->
14 | Aeson.Encode.string "Hearts"
15 | | Spades ->
16 | Aeson.Encode.string "Spades"
17 |
18 | let decodeSuit json =
19 | match Js_json.decodeString json with
20 | | Some "Clubs" -> Belt.Result.Ok Clubs
21 | | Some "Diamonds" -> Belt.Result.Ok Diamonds
22 | | Some "Hearts" -> Belt.Result.Ok Hearts
23 | | Some "Spades" -> Belt.Result.Ok Spades
24 | | Some err -> Belt.Result.Error ("decodeSuit: unknown enumeration '" ^ err ^ "'.")
25 | | None -> Belt.Result.Error "decodeSuit: expected a top-level JSON string."
26 |
27 | type card =
28 | { cardSuit : suit
29 | ; cardValue : int
30 | }
31 |
32 | let encodeCard x =
33 | Aeson.Encode.object_
34 | [ ( "cardSuit", encodeSuit x.cardSuit )
35 | ; ( "cardValue", Aeson.Encode.int x.cardValue )
36 | ]
37 |
38 | let decodeCard json =
39 | match Aeson.Decode.
40 | { cardSuit = field "cardSuit" (fun a -> unwrapResult (decodeSuit a)) json
41 | ; cardValue = field "cardValue" int json
42 | }
43 | with
44 | | v -> Belt.Result.Ok v
45 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeCard: " ^ message)
46 |
--------------------------------------------------------------------------------
/test/interface/golden/product/Card.mli:
--------------------------------------------------------------------------------
1 | type suit =
2 | | Clubs
3 | | Diamonds
4 | | Hearts
5 | | Spades
6 |
7 | val encodeSuit : suit -> Js_json.t
8 |
9 | val decodeSuit : Js_json.t -> (suit, string) Belt.Result.t
10 |
11 | type card =
12 | { cardSuit : suit
13 | ; cardValue : int
14 | }
15 |
16 | val encodeCard : card -> Js_json.t
17 |
18 | val decodeCard : Js_json.t -> (card, string) Belt.Result.t
19 |
--------------------------------------------------------------------------------
/test/interface/golden/product/Company.ml:
--------------------------------------------------------------------------------
1 | type company =
2 | { address : string
3 | ; employees : (Person.person) list
4 | }
5 |
6 | let encodeCompany x =
7 | Aeson.Encode.object_
8 | [ ( "address", Aeson.Encode.string x.address )
9 | ; ( "employees", (Aeson.Encode.list Person.encodePerson) x.employees )
10 | ]
11 |
12 | let decodeCompany json =
13 | match Aeson.Decode.
14 | { address = field "address" string json
15 | ; employees = field "employees" (list (fun a -> unwrapResult (Person.decodePerson a))) json
16 | }
17 | with
18 | | v -> Belt.Result.Ok v
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeCompany: " ^ message)
20 |
--------------------------------------------------------------------------------
/test/interface/golden/product/Company.mli:
--------------------------------------------------------------------------------
1 | type company =
2 | { address : string
3 | ; employees : (Person.person) list
4 | }
5 |
6 | val encodeCompany : company -> Js_json.t
7 |
8 | val decodeCompany : Js_json.t -> (company, string) Belt.Result.t
9 |
--------------------------------------------------------------------------------
/test/interface/golden/product/ComplexProduct.ml:
--------------------------------------------------------------------------------
1 | type simple =
2 | { sa : int
3 | ; sb : string
4 | }
5 |
6 | let encodeSimple x =
7 | Aeson.Encode.object_
8 | [ ( "sa", Aeson.Encode.int x.sa )
9 | ; ( "sb", Aeson.Encode.string x.sb )
10 | ]
11 |
12 | let decodeSimple json =
13 | match Aeson.Decode.
14 | { sa = field "sa" int json
15 | ; sb = field "sb" string json
16 | }
17 | with
18 | | v -> Belt.Result.Ok v
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeSimple: " ^ message)
20 |
21 |
22 | type complexProduct =
23 | { cp0 : (Person.person, (int) list) Aeson.Compatibility.Either.t
24 | ; cp1 : ((int * (string, float) Aeson.Compatibility.Either.t)) list
25 | ; cp2 : ((int) list) list
26 | ; cp3 : ((int) list) option
27 | ; cp4 : (simple, int) Aeson.Compatibility.Either.t
28 | }
29 |
30 | let encodeComplexProduct x =
31 | Aeson.Encode.object_
32 | [ ( "cp0", (Aeson.Encode.either Person.encodePerson (Aeson.Encode.list Aeson.Encode.int)) x.cp0 )
33 | ; ( "cp1", (Aeson.Encode.list (Aeson.Encode.pair Aeson.Encode.int (Aeson.Encode.either Aeson.Encode.string Aeson.Encode.float))) x.cp1 )
34 | ; ( "cp2", (Aeson.Encode.list (Aeson.Encode.list Aeson.Encode.int)) x.cp2 )
35 | ; ( "cp3", (Aeson.Encode.optional (Aeson.Encode.list Aeson.Encode.int)) x.cp3 )
36 | ; ( "cp4", (Aeson.Encode.either encodeSimple Aeson.Encode.int) x.cp4 )
37 | ]
38 |
39 | let decodeComplexProduct json =
40 | match Aeson.Decode.
41 | { cp0 = field "cp0" (either (fun a -> unwrapResult (Person.decodePerson a)) (list int)) json
42 | ; cp1 = field "cp1" (list (pair int (either string Aeson.Decode.float))) json
43 | ; cp2 = field "cp2" (list (list int)) json
44 | ; cp3 = field "cp3" (optional (list int)) json
45 | ; cp4 = field "cp4" (either (fun a -> unwrapResult (decodeSimple a)) int) json
46 | }
47 | with
48 | | v -> Belt.Result.Ok v
49 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeComplexProduct: " ^ message)
50 |
--------------------------------------------------------------------------------
/test/interface/golden/product/ComplexProduct.mli:
--------------------------------------------------------------------------------
1 | type simple =
2 | { sa : int
3 | ; sb : string
4 | }
5 |
6 | val encodeSimple : simple -> Js_json.t
7 |
8 | val decodeSimple : Js_json.t -> (simple, string) Belt.Result.t
9 |
10 |
11 | type complexProduct =
12 | { cp0 : (Person.person, (int) list) Aeson.Compatibility.Either.t
13 | ; cp1 : ((int * (string, float) Aeson.Compatibility.Either.t)) list
14 | ; cp2 : ((int) list) list
15 | ; cp3 : ((int) list) option
16 | ; cp4 : (simple, int) Aeson.Compatibility.Either.t
17 | }
18 |
19 | val encodeComplexProduct : complexProduct -> Js_json.t
20 |
21 | val decodeComplexProduct : Js_json.t -> (complexProduct, string) Belt.Result.t
22 |
--------------------------------------------------------------------------------
/test/interface/golden/product/CustomOption.ml:
--------------------------------------------------------------------------------
1 | type company2 =
2 | { address2 : string
3 | ; boss : (Person.person) option
4 | }
5 |
6 | let encodeCompany2 x =
7 | Aeson.Encode.object_
8 | [ ( "address2", Aeson.Encode.string x.address2 )
9 | ; ( "boss", Aeson.Encode.optional Person.encodePerson x.boss )
10 | ]
11 |
12 | let decodeCompany2 json =
13 | match Aeson.Decode.
14 | { address2 = field "address2" string json
15 | ; boss = optional (field "boss" (fun a -> unwrapResult (Person.decodePerson a))) json
16 | }
17 | with
18 | | v -> Belt.Result.Ok v
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeCompany2: " ^ message)
20 |
--------------------------------------------------------------------------------
/test/interface/golden/product/CustomOption.mli:
--------------------------------------------------------------------------------
1 | type company2 =
2 | { address2 : string
3 | ; boss : (Person.person) option
4 | }
5 |
6 | val encodeCompany2 : company2 -> Js_json.t
7 |
8 | val decodeCompany2 : Js_json.t -> (company2, string) Belt.Result.t
9 |
--------------------------------------------------------------------------------
/test/interface/golden/product/Key.ml:
--------------------------------------------------------------------------------
1 | type sqlKey =
2 | | SqlKey of int
3 |
4 | let encodeSqlKey x =
5 | match x with
6 | | SqlKey y0 ->
7 | Aeson.Encode.int y0
8 |
9 | let decodeSqlKey json =
10 | match Aeson.Decode.int json with
11 | | v -> Belt.Result.Ok (SqlKey v)
12 | | exception Aeson.Decode.DecodeError msg -> Belt.Result.Error ("decodeSqlKey: " ^ msg)
13 |
14 | type userId =
15 | | UserId of sqlKey
16 |
17 | let encodeUserId x =
18 | match x with
19 | | UserId y0 ->
20 | encodeSqlKey y0
21 |
22 | let decodeUserId json =
23 | match (Aeson.Decode.unwrapResult (decodeSqlKey json)) with
24 | | v -> Belt.Result.Ok (UserId v)
25 | | exception Aeson.Decode.DecodeError msg -> Belt.Result.Error ("decodeUserId: " ^ msg)
26 |
--------------------------------------------------------------------------------
/test/interface/golden/product/Key.mli:
--------------------------------------------------------------------------------
1 | type sqlKey =
2 | | SqlKey of int
3 |
4 | val encodeSqlKey : sqlKey -> Js_json.t
5 |
6 | val decodeSqlKey : Js_json.t -> (sqlKey, string) Belt.Result.t
7 |
8 | type userId =
9 | | UserId of sqlKey
10 |
11 | val encodeUserId : userId -> Js_json.t
12 |
13 | val decodeUserId : Js_json.t -> (userId, string) Belt.Result.t
14 |
--------------------------------------------------------------------------------
/test/interface/golden/product/OneTypeParameter.ml:
--------------------------------------------------------------------------------
1 | type 'a0 oneTypeParameter =
2 | { otpId : int
3 | ; otpFirst : 'a0
4 | }
5 |
6 | let encodeOneTypeParameter encodeA0 x =
7 | Aeson.Encode.object_
8 | [ ( "otpId", Aeson.Encode.int x.otpId )
9 | ; ( "otpFirst", encodeA0 x.otpFirst )
10 | ]
11 |
12 | let decodeOneTypeParameter decodeA0 json =
13 | match Aeson.Decode.
14 | { otpId = field "otpId" int json
15 | ; otpFirst = field "otpFirst" (fun a -> unwrapResult (decodeA0 a)) json
16 | }
17 | with
18 | | v -> Belt.Result.Ok v
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeOneTypeParameter: " ^ message)
20 |
--------------------------------------------------------------------------------
/test/interface/golden/product/OneTypeParameter.mli:
--------------------------------------------------------------------------------
1 | type 'a0 oneTypeParameter =
2 | { otpId : int
3 | ; otpFirst : 'a0
4 | }
5 |
6 | val encodeOneTypeParameter : ('a0 -> Js_json.t) -> 'a0 oneTypeParameter -> Js_json.t
7 |
8 | val decodeOneTypeParameter : (Js_json.t -> ('a0, string) Belt.Result.t) -> Js_json.t -> ('a0 oneTypeParameter, string) Belt.Result.t
9 |
--------------------------------------------------------------------------------
/test/interface/golden/product/Person.ml:
--------------------------------------------------------------------------------
1 | type person =
2 | { id : int
3 | ; name : (string) option
4 | ; created : Js_date.t
5 | }
6 |
7 | let encodePerson x =
8 | Aeson.Encode.object_
9 | [ ( "id", Aeson.Encode.int x.id )
10 | ; ( "name", (Aeson.Encode.optional Aeson.Encode.string) x.name )
11 | ; ( "created", Aeson.Encode.date x.created )
12 | ]
13 |
14 | let decodePerson json =
15 | match Aeson.Decode.
16 | { id = field "id" int json
17 | ; name = field "name" (optional string) json
18 | ; created = field "created" date json
19 | }
20 | with
21 | | v -> Belt.Result.Ok v
22 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodePerson: " ^ message)
23 |
--------------------------------------------------------------------------------
/test/interface/golden/product/Person.mli:
--------------------------------------------------------------------------------
1 | type person =
2 | { id : int
3 | ; name : (string) option
4 | ; created : Js_date.t
5 | }
6 |
7 | val encodePerson : person -> Js_json.t
8 |
9 | val decodePerson : Js_json.t -> (person, string) Belt.Result.t
10 |
--------------------------------------------------------------------------------
/test/interface/golden/product/SimpleChoice.ml:
--------------------------------------------------------------------------------
1 | type simpleChoice =
2 | { choice : (string, int) Aeson.Compatibility.Either.t
3 | }
4 |
5 | let encodeSimpleChoice x =
6 | Aeson.Encode.object_
7 | [ ( "choice", Aeson.Encode.either Aeson.Encode.string Aeson.Encode.int x.choice )
8 | ]
9 |
10 | let decodeSimpleChoice json =
11 | match Aeson.Decode.
12 | { choice = field "choice" (either string int) json
13 | }
14 | with
15 | | v -> Belt.Result.Ok v
16 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeSimpleChoice: " ^ message)
17 |
--------------------------------------------------------------------------------
/test/interface/golden/product/SimpleChoice.mli:
--------------------------------------------------------------------------------
1 | type simpleChoice =
2 | { choice : (string, int) Aeson.Compatibility.Either.t
3 | }
4 |
5 | val encodeSimpleChoice : simpleChoice -> Js_json.t
6 |
7 | val decodeSimpleChoice : Js_json.t -> (simpleChoice, string) Belt.Result.t
8 |
--------------------------------------------------------------------------------
/test/interface/golden/product/SubTypeParameter.ml:
--------------------------------------------------------------------------------
1 | type ('a0, 'a1, 'a2) subTypeParameter =
2 | { listA : ('a0) list
3 | ; maybeB : ('a1) option
4 | ; tupleC : ('a2 * 'a1)
5 | }
6 |
7 | let encodeSubTypeParameter encodeA0 encodeA1 encodeA2 x =
8 | Aeson.Encode.object_
9 | [ ( "listA", (Aeson.Encode.list encodeA0) x.listA )
10 | ; ( "maybeB", (Aeson.Encode.optional encodeA1) x.maybeB )
11 | ; ( "tupleC", (Aeson.Encode.pair encodeA2 encodeA1) x.tupleC )
12 | ]
13 |
14 | let decodeSubTypeParameter decodeA0 decodeA1 decodeA2 json =
15 | match Aeson.Decode.
16 | { listA = field "listA" (list (fun a -> unwrapResult (decodeA0 a))) json
17 | ; maybeB = field "maybeB" (optional (fun a -> unwrapResult (decodeA1 a))) json
18 | ; tupleC = field "tupleC" (pair (fun a -> unwrapResult (decodeA2 a)) (fun a -> unwrapResult (decodeA1 a))) json
19 | }
20 | with
21 | | v -> Belt.Result.Ok v
22 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeSubTypeParameter: " ^ message)
23 |
--------------------------------------------------------------------------------
/test/interface/golden/product/SubTypeParameter.mli:
--------------------------------------------------------------------------------
1 | type ('a0, 'a1, 'a2) subTypeParameter =
2 | { listA : ('a0) list
3 | ; maybeB : ('a1) option
4 | ; tupleC : ('a2 * 'a1)
5 | }
6 |
7 | val encodeSubTypeParameter : ('a0 -> Js_json.t) -> ('a1 -> Js_json.t) -> ('a2 -> Js_json.t) -> ('a0, 'a1, 'a2) subTypeParameter -> Js_json.t
8 |
9 | val decodeSubTypeParameter : (Js_json.t -> ('a0, string) Belt.Result.t) -> (Js_json.t -> ('a1, string) Belt.Result.t) -> (Js_json.t -> ('a2, string) Belt.Result.t) -> Js_json.t -> (('a0, 'a1, 'a2) subTypeParameter, string) Belt.Result.t
10 |
--------------------------------------------------------------------------------
/test/interface/golden/product/ThreeTypeParameters.ml:
--------------------------------------------------------------------------------
1 | type ('a0, 'a1, 'a2) three =
2 | { threeId : int
3 | ; threeFirst : 'a0
4 | ; threeSecond : 'a1
5 | ; threeThird : 'a2
6 | ; threeString : string
7 | }
8 |
9 | let encodeThree encodeA0 encodeA1 encodeA2 x =
10 | Aeson.Encode.object_
11 | [ ( "threeId", Aeson.Encode.int x.threeId )
12 | ; ( "threeFirst", encodeA0 x.threeFirst )
13 | ; ( "threeSecond", encodeA1 x.threeSecond )
14 | ; ( "threeThird", encodeA2 x.threeThird )
15 | ; ( "threeString", Aeson.Encode.string x.threeString )
16 | ]
17 |
18 | let decodeThree decodeA0 decodeA1 decodeA2 json =
19 | match Aeson.Decode.
20 | { threeId = field "threeId" int json
21 | ; threeFirst = field "threeFirst" (fun a -> unwrapResult (decodeA0 a)) json
22 | ; threeSecond = field "threeSecond" (fun a -> unwrapResult (decodeA1 a)) json
23 | ; threeThird = field "threeThird" (fun a -> unwrapResult (decodeA2 a)) json
24 | ; threeString = field "threeString" string json
25 | }
26 | with
27 | | v -> Belt.Result.Ok v
28 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeThree: " ^ message)
29 |
--------------------------------------------------------------------------------
/test/interface/golden/product/ThreeTypeParameters.mli:
--------------------------------------------------------------------------------
1 | type ('a0, 'a1, 'a2) three =
2 | { threeId : int
3 | ; threeFirst : 'a0
4 | ; threeSecond : 'a1
5 | ; threeThird : 'a2
6 | ; threeString : string
7 | }
8 |
9 | val encodeThree : ('a0 -> Js_json.t) -> ('a1 -> Js_json.t) -> ('a2 -> Js_json.t) -> ('a0, 'a1, 'a2) three -> Js_json.t
10 |
11 | val decodeThree : (Js_json.t -> ('a0, string) Belt.Result.t) -> (Js_json.t -> ('a1, string) Belt.Result.t) -> (Js_json.t -> ('a2, string) Belt.Result.t) -> Js_json.t -> (('a0, 'a1, 'a2) three, string) Belt.Result.t
12 |
--------------------------------------------------------------------------------
/test/interface/golden/product/TwoTypeParameters.ml:
--------------------------------------------------------------------------------
1 | type ('a0, 'a1) twoTypeParameters =
2 | { ttpId : int
3 | ; ttpFirst : 'a0
4 | ; ttpSecond : 'a1
5 | ; ttpThird : ('a0 * 'a1)
6 | }
7 |
8 | let encodeTwoTypeParameters encodeA0 encodeA1 x =
9 | Aeson.Encode.object_
10 | [ ( "ttpId", Aeson.Encode.int x.ttpId )
11 | ; ( "ttpFirst", encodeA0 x.ttpFirst )
12 | ; ( "ttpSecond", encodeA1 x.ttpSecond )
13 | ; ( "ttpThird", (Aeson.Encode.pair encodeA0 encodeA1) x.ttpThird )
14 | ]
15 |
16 | let decodeTwoTypeParameters decodeA0 decodeA1 json =
17 | match Aeson.Decode.
18 | { ttpId = field "ttpId" int json
19 | ; ttpFirst = field "ttpFirst" (fun a -> unwrapResult (decodeA0 a)) json
20 | ; ttpSecond = field "ttpSecond" (fun a -> unwrapResult (decodeA1 a)) json
21 | ; ttpThird = field "ttpThird" (pair (fun a -> unwrapResult (decodeA0 a)) (fun a -> unwrapResult (decodeA1 a))) json
22 | }
23 | with
24 | | v -> Belt.Result.Ok v
25 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeTwoTypeParameters: " ^ message)
26 |
--------------------------------------------------------------------------------
/test/interface/golden/product/TwoTypeParameters.mli:
--------------------------------------------------------------------------------
1 | type ('a0, 'a1) twoTypeParameters =
2 | { ttpId : int
3 | ; ttpFirst : 'a0
4 | ; ttpSecond : 'a1
5 | ; ttpThird : ('a0 * 'a1)
6 | }
7 |
8 | val encodeTwoTypeParameters : ('a0 -> Js_json.t) -> ('a1 -> Js_json.t) -> ('a0, 'a1) twoTypeParameters -> Js_json.t
9 |
10 | val decodeTwoTypeParameters : (Js_json.t -> ('a0, string) Belt.Result.t) -> (Js_json.t -> ('a1, string) Belt.Result.t) -> Js_json.t -> (('a0, 'a1) twoTypeParameters, string) Belt.Result.t
11 |
--------------------------------------------------------------------------------
/test/interface/golden/product/UnnamedProduct.ml:
--------------------------------------------------------------------------------
1 | type unnamedProduct =
2 | | UnnamedProduct of string * int
3 |
4 | let encodeUnnamedProduct x =
5 | match x with
6 | | UnnamedProduct (y0,y1) ->
7 | Aeson.Encode.array [| Aeson.Encode.string y0 ; Aeson.Encode.int y1 |]
8 |
9 | let decodeUnnamedProduct json =
10 | match Js.Json.decodeArray json with
11 | | Some v ->
12 | (match Aeson.Decode.(string) v.(0) with
13 | | v0 ->
14 | (match Aeson.Decode.(int) v.(1) with
15 | | v1 ->
16 | Belt.Result.Ok (UnnamedProduct (v0, v1))
17 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("UnnamedProduct: " ^ message)
18 | )
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("UnnamedProduct: " ^ message)
20 | )
21 | | None -> Belt.Result.Error ("UnnamedProduct expected an array.")
22 |
--------------------------------------------------------------------------------
/test/interface/golden/product/UnnamedProduct.mli:
--------------------------------------------------------------------------------
1 | type unnamedProduct =
2 | | UnnamedProduct of string * int
3 |
4 | val encodeUnnamedProduct : unnamedProduct -> Js_json.t
5 |
6 | val decodeUnnamedProduct : Js_json.t -> (unnamedProduct, string) Belt.Result.t
7 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/NameOrIdNumber.ml:
--------------------------------------------------------------------------------
1 | type nameOrIdNumber =
2 | | Name of string
3 | | IdNumber of int
4 |
5 | let encodeNameOrIdNumber x =
6 | match x with
7 | | Name y0 ->
8 | Aeson.Encode.object_
9 | [ ( "tag", Aeson.Encode.string "Name" )
10 | ; ( "contents", Aeson.Encode.string y0 )
11 | ]
12 | | IdNumber y0 ->
13 | Aeson.Encode.object_
14 | [ ( "tag", Aeson.Encode.string "IdNumber" )
15 | ; ( "contents", Aeson.Encode.int y0 )
16 | ]
17 |
18 | let decodeNameOrIdNumber json =
19 | match Aeson.Decode.(field "tag" string json) with
20 | | "Name" ->
21 | (match Aeson.Decode.(field "contents" string json) with
22 | | v -> Belt.Result.Ok (Name v)
23 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("Name: " ^ message)
24 | )
25 | | "IdNumber" ->
26 | (match Aeson.Decode.(field "contents" int json) with
27 | | v -> Belt.Result.Ok (IdNumber v)
28 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("IdNumber: " ^ message)
29 | )
30 | | err -> Belt.Result.Error ("Unknown tag value found '" ^ err ^ "'.")
31 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error message
32 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/NameOrIdNumber.mli:
--------------------------------------------------------------------------------
1 | type nameOrIdNumber =
2 | | Name of string
3 | | IdNumber of int
4 |
5 | val encodeNameOrIdNumber : nameOrIdNumber -> Js_json.t
6 |
7 | val decodeNameOrIdNumber : Js_json.t -> (nameOrIdNumber, string) Belt.Result.t
8 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/NewType.ml:
--------------------------------------------------------------------------------
1 | type newType =
2 | | NewType of int
3 |
4 | let encodeNewType x =
5 | match x with
6 | | NewType y0 ->
7 | Aeson.Encode.int y0
8 |
9 | let decodeNewType json =
10 | match Aeson.Decode.int json with
11 | | v -> Belt.Result.Ok (NewType v)
12 | | exception Aeson.Decode.DecodeError msg -> Belt.Result.Error ("decodeNewType: " ^ msg)
13 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/NewType.mli:
--------------------------------------------------------------------------------
1 | type newType =
2 | | NewType of int
3 |
4 | val encodeNewType : newType -> Js_json.t
5 |
6 | val decodeNewType : Js_json.t -> (newType, string) Belt.Result.t
7 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/OnOrOff.ml:
--------------------------------------------------------------------------------
1 | type onOrOff =
2 | | On
3 | | Off
4 |
5 | let encodeOnOrOff x =
6 | match x with
7 | | On ->
8 | Aeson.Encode.string "On"
9 | | Off ->
10 | Aeson.Encode.string "Off"
11 |
12 | let decodeOnOrOff json =
13 | match Js_json.decodeString json with
14 | | Some "On" -> Belt.Result.Ok On
15 | | Some "Off" -> Belt.Result.Ok Off
16 | | Some err -> Belt.Result.Error ("decodeOnOrOff: unknown enumeration '" ^ err ^ "'.")
17 | | None -> Belt.Result.Error "decodeOnOrOff: expected a top-level JSON string."
18 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/OnOrOff.mli:
--------------------------------------------------------------------------------
1 | type onOrOff =
2 | | On
3 | | Off
4 |
5 | val encodeOnOrOff : onOrOff -> Js_json.t
6 |
7 | val decodeOnOrOff : Js_json.t -> (onOrOff, string) Belt.Result.t
8 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/Result.ml:
--------------------------------------------------------------------------------
1 | type ('a0, 'a1) result =
2 | | Success of 'a0
3 | | Error of 'a1
4 |
5 | let encodeResult encodeA0 encodeA1 x =
6 | match x with
7 | | Success y0 ->
8 | Aeson.Encode.object_
9 | [ ( "tag", Aeson.Encode.string "Success" )
10 | ; ( "contents", encodeA0 y0 )
11 | ]
12 | | Error y0 ->
13 | Aeson.Encode.object_
14 | [ ( "tag", Aeson.Encode.string "Error" )
15 | ; ( "contents", encodeA1 y0 )
16 | ]
17 |
18 | let decodeResult decodeA0 decodeA1 json =
19 | match Aeson.Decode.(field "tag" string json) with
20 | | "Success" ->
21 | (match Aeson.Decode.(field "contents" (fun a -> unwrapResult (decodeA0 a)) json) with
22 | | v -> Belt.Result.Ok (Success v)
23 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("Success: " ^ message)
24 | )
25 | | "Error" ->
26 | (match Aeson.Decode.(field "contents" (fun a -> unwrapResult (decodeA1 a)) json) with
27 | | v -> Belt.Result.Ok (Error v)
28 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("Error: " ^ message)
29 | )
30 | | err -> Belt.Result.Error ("Unknown tag value found '" ^ err ^ "'.")
31 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error message
32 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/Result.mli:
--------------------------------------------------------------------------------
1 | type ('a0, 'a1) result =
2 | | Success of 'a0
3 | | Error of 'a1
4 |
5 | val encodeResult : ('a0 -> Js_json.t) -> ('a1 -> Js_json.t) -> ('a0, 'a1) result -> Js_json.t
6 |
7 | val decodeResult : (Js_json.t -> ('a0, string) Belt.Result.t) -> (Js_json.t -> ('a1, string) Belt.Result.t) -> Js_json.t -> (('a0, 'a1) result, string) Belt.Result.t
8 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/SingleSum.ml:
--------------------------------------------------------------------------------
1 | type singleSum =
2 | | SingleSum
3 |
4 | let encodeSingleSum x =
5 | match x with
6 | | SingleSum ->
7 | Aeson.Encode.list Aeson.Encode.int []
8 |
9 | let decodeSingleSum json =
10 | match (Aeson.Decode.(list int json)) with
11 | | _ -> Belt.Result.Ok SingleSum
12 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeSingleSum: expected a top-level empty JSON array. Got: " ^ message)
13 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/SingleSum.mli:
--------------------------------------------------------------------------------
1 | type singleSum =
2 | | SingleSum
3 |
4 | val encodeSingleSum : singleSum -> Js_json.t
5 |
6 | val decodeSingleSum : Js_json.t -> (singleSum, string) Belt.Result.t
7 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/SumVariant.mli:
--------------------------------------------------------------------------------
1 | type sumVariant =
2 | | HasNothing
3 | | HasSingleInt of int
4 | | HasSingleTuple of (int * int)
5 | | HasMultipleInts of int * int
6 | | HasMultipleTuples of (int * int) * (int * int)
7 | | HasMixed of int * string * float
8 | | HasNameOrIdNumber of NameOrIdNumber.nameOrIdNumber * int
9 |
10 | val encodeSumVariant : sumVariant -> Js_json.t
11 |
12 | val decodeSumVariant : Js_json.t -> (sumVariant, string) Belt.Result.t
13 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/SumWithRecord.ml:
--------------------------------------------------------------------------------
1 | type sumWithRecordA1 =
2 | { a1 : int
3 | }
4 |
5 | type sumWithRecordB2 =
6 | { b2 : string
7 | ; b3 : int
8 | }
9 |
10 | type sumWithRecord =
11 | | A1 of sumWithRecordA1
12 | | B2 of sumWithRecordB2
13 |
14 | let encodeSumWithRecordA1 x =
15 | Aeson.Encode.object_
16 | [ ( "a1", Aeson.Encode.int x.a1 )
17 | ]
18 |
19 | let encodeSumWithRecordB2 x =
20 | Aeson.Encode.object_
21 | [ ( "b2", Aeson.Encode.string x.b2 )
22 | ; ( "b3", Aeson.Encode.int x.b3 )
23 | ]
24 |
25 | let encodeSumWithRecord x =
26 | match x with
27 | | A1 y0 ->
28 | (match (Js.Json.decodeObject (encodeSumWithRecordA1 y0)) with
29 | | Some dict ->
30 | Js.Dict.set dict "tag" (Js.Json.string "A1");
31 | Js.Json.object_ dict
32 | | None ->
33 | Aeson.Encode.object_ []
34 | )
35 | | B2 y0 ->
36 | (match (Js.Json.decodeObject (encodeSumWithRecordB2 y0)) with
37 | | Some dict ->
38 | Js.Dict.set dict "tag" (Js.Json.string "B2");
39 | Js.Json.object_ dict
40 | | None ->
41 | Aeson.Encode.object_ []
42 | )
43 |
44 | let decodeSumWithRecordA1 json =
45 | match Aeson.Decode.
46 | { a1 = field "a1" int json
47 | }
48 | with
49 | | v -> Belt.Result.Ok v
50 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeSumWithRecordA1: " ^ message)
51 |
52 | let decodeSumWithRecordB2 json =
53 | match Aeson.Decode.
54 | { b2 = field "b2" string json
55 | ; b3 = field "b3" int json
56 | }
57 | with
58 | | v -> Belt.Result.Ok v
59 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeSumWithRecordB2: " ^ message)
60 |
61 | let decodeSumWithRecord json =
62 | match Aeson.Decode.(field "tag" string json) with
63 | | "A1" ->
64 | (match decodeSumWithRecordA1 json with
65 | | Belt.Result.Ok v -> Belt.Result.Ok (A1 v)
66 | | Belt.Result.Error message -> Belt.Result.Error ("decodeSumWithRecord: " ^ message)
67 | )
68 | | "B2" ->
69 | (match decodeSumWithRecordB2 json with
70 | | Belt.Result.Ok v -> Belt.Result.Ok (B2 v)
71 | | Belt.Result.Error message -> Belt.Result.Error ("decodeSumWithRecord: " ^ message)
72 | )
73 | | err -> Belt.Result.Error ("Unknown tag value found '" ^ err ^ "'.")
74 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error message
75 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/SumWithRecord.mli:
--------------------------------------------------------------------------------
1 | type sumWithRecordA1 =
2 | { a1 : int
3 | }
4 |
5 | type sumWithRecordB2 =
6 | { b2 : string
7 | ; b3 : int
8 | }
9 |
10 | type sumWithRecord =
11 | | A1 of sumWithRecordA1
12 | | B2 of sumWithRecordB2
13 |
14 | val encodeSumWithRecordA1 : sumWithRecordA1 -> Js_json.t
15 |
16 | val encodeSumWithRecordB2 : sumWithRecordB2 -> Js_json.t
17 |
18 | val encodeSumWithRecord : sumWithRecord -> Js_json.t
19 |
20 | val decodeSumWithRecordA1 : Js_json.t -> (sumWithRecordA1, string) Belt.Result.t
21 |
22 | val decodeSumWithRecordB2 : Js_json.t -> (sumWithRecordB2, string) Belt.Result.t
23 |
24 | val decodeSumWithRecord : Js_json.t -> (sumWithRecord, string) Belt.Result.t
25 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/WithTuple.ml:
--------------------------------------------------------------------------------
1 | type withTuple =
2 | | WithTuple of (int * int)
3 |
4 | let encodeWithTuple x =
5 | match x with
6 | | WithTuple y0 ->
7 | (Aeson.Encode.pair Aeson.Encode.int Aeson.Encode.int) y0
8 |
9 | let decodeWithTuple json =
10 | match Aeson.Decode.(pair int int) json with
11 | | v -> Belt.Result.Ok (WithTuple v)
12 | | exception Aeson.Decode.DecodeError msg -> Belt.Result.Error ("decodeWithTuple: " ^ msg)
13 |
--------------------------------------------------------------------------------
/test/interface/golden/sum/WithTuple.mli:
--------------------------------------------------------------------------------
1 | type withTuple =
2 | | WithTuple of (int * int)
3 |
4 | val encodeWithTuple : withTuple -> Js_json.t
5 |
6 | val decodeWithTuple : Js_json.t -> (withTuple, string) Belt.Result.t
7 |
--------------------------------------------------------------------------------
/test/interface/golden/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: {
5 | onping: './lib/js/src/App.js'
6 | },
7 | output: {
8 | path: path.join(__dirname, "bundledOutputs"),
9 | filename: '[name].js',
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/test/ocaml/Business.ml:
--------------------------------------------------------------------------------
1 | type business =
2 | { taxId : string
3 | ; owner : person
4 | ; employees : (person) list
5 | ; companyVehicle : (automobile) option
6 | }
7 |
8 | let encodeBusiness x =
9 | Aeson.Encode.object_
10 | [ ( "taxId", Aeson.Encode.string x.taxId )
11 | ; ( "owner", encodePerson x.owner )
12 | ; ( "employees", (Aeson.Encode.list encodePerson) x.employees )
13 | ; ( "companyVehicle", Aeson.Encode.optional encodeAutomobile x.companyVehicle )
14 | ]
15 |
16 | let decodeBusiness json =
17 | match Aeson.Decode.
18 | { taxId = field "taxId" string json
19 | ; owner = field "owner" (fun a -> unwrapResult (decodePerson a)) json
20 | ; employees = field "employees" (list (fun a -> unwrapResult (decodePerson a))) json
21 | ; companyVehicle = optional (field "companyVehicle" (fun a -> unwrapResult (decodeAutomobile a))) json
22 | }
23 | with
24 | | v -> Belt.Result.Ok v
25 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeBusiness: " ^ message)
26 |
--------------------------------------------------------------------------------
/test/ocaml/Business.mli:
--------------------------------------------------------------------------------
1 | type business =
2 | { taxId : string
3 | ; owner : person
4 | ; employees : (person) list
5 | ; companyVehicle : (automobile) option
6 | }
7 |
8 | val encodeBusiness : business -> Js_json.t
9 |
10 | val decodeBusiness : Js_json.t -> (business, string) Belt.Result.t
11 |
--------------------------------------------------------------------------------
/test/ocaml/NonGenericType.ml:
--------------------------------------------------------------------------------
1 | type nonGenericType =
2 | { ngA : string
3 | ; ngB : int
4 | }
5 |
6 | let encodeNonGenericType x =
7 | Aeson.Encode.object_
8 | [ ( "ngA", Aeson.Encode.string x.ngA)
9 | ; ( "ngB", Aeson.Encode.int x.ngB)
10 | ]
11 |
12 | let decodeNonGenericType json =
13 | match Aeson.Decode.
14 | { ngA = field "ngA" string json
15 | ; ngB = field "ngB" int json
16 | }
17 | with
18 | | v -> Belt.Result.Ok v
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeNonGenericType: " ^ message)
20 |
--------------------------------------------------------------------------------
/test/ocaml/NonGenericType.mli:
--------------------------------------------------------------------------------
1 | type nonGenericType =
2 | { ngA : string
3 | ; ngB : int
4 | }
5 |
6 | val encodeNonGenericType : nonGenericType -> Js_json.t
7 |
8 | val decodeNonGenericType : Js_json.t -> (nonGenericType, string) Belt.Result.t
9 |
--------------------------------------------------------------------------------
/test/ocaml/Person.ml:
--------------------------------------------------------------------------------
1 | type person =
2 | { id : int
3 | ; name : (string) option
4 | }
5 |
6 | let encodePerson x =
7 | Aeson.Encode.object_
8 | [ ( "id", Aeson.Encode.int x.id )
9 | ; ( "name", Aeson.Encode.optional Aeson.Encode.string x.name )
10 | ]
11 |
12 | let decodePerson json =
13 | match Aeson.Decode.
14 | { id = field "id" int json
15 | ; name = optional (field "name" string) json
16 | }
17 | with
18 | | v -> Belt.Result.Ok v
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodePerson: " ^ message)
20 |
--------------------------------------------------------------------------------
/test/ocaml/Person.mli:
--------------------------------------------------------------------------------
1 | type person =
2 | { id : int
3 | ; name : (string) option
4 | }
5 |
6 | val encodePerson : person -> Js_json.t
7 |
8 | val decodePerson : Js_json.t -> (person, string) Belt.Result.t
9 |
--------------------------------------------------------------------------------
/test/ocaml/Simple.ml:
--------------------------------------------------------------------------------
1 | type simple =
2 | { sa : int
3 | ; sb : string
4 | }
5 |
6 | let encodeSimple x =
7 | Aeson.Encode.object_
8 | [ ( "sa", Aeson.Encode.int x.sa )
9 | ; ( "sb", Aeson.Encode.string x.sb )
10 | ]
11 |
12 | let decodeSimple json =
13 | match Aeson.Decode.
14 | { sa = field "sa" int json
15 | ; sb = field "sb" string json
16 | }
17 | with
18 | | v -> Belt.Result.Ok v
19 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeSimple: " ^ message)
20 |
--------------------------------------------------------------------------------
/test/ocaml/Simple.mli:
--------------------------------------------------------------------------------
1 | type simple =
2 | { sa : int
3 | ; sb : string
4 | }
5 |
6 | val encodeSimple : simple -> Js_json.t
7 |
8 | val decodeSimple : Js_json.t -> (simple, string) Belt.Result.t
9 |
--------------------------------------------------------------------------------
/test/ocaml/Wrapper.ml:
--------------------------------------------------------------------------------
1 | type ('a, 'b) wrapper =
2 | { wrapperA : 'a
3 | ; wrapperB : 'b
4 | ; wrapperC : string
5 | }
6 |
7 | let encodeWrapper a b x =
8 | Aeson.Encode.object_
9 | [ ( "wrapperA", a x.wrapperA )
10 | ; ( "wrapperB", b x.wrapperB )
11 | ; ( "wrapperC", Aeson.Encode.string x.wrapperC )
12 | ]
13 |
14 | let decodeWrapper a b json =
15 | match Aeson.Decode.
16 | { wrapperA = field "wrapperA" (fun x -> unwrapResult (a x)) json
17 | ; wrapperB = field "wrapperB" (fun x -> unwrapResult (b x)) json
18 | ; wrapperC = field "wrapperC" string json
19 | }
20 | with
21 | | v -> Belt.Result.Ok v
22 | | exception Aeson.Decode.DecodeError message -> Belt.Result.Error ("decodeWrapper: " ^ message)
23 |
--------------------------------------------------------------------------------
/test/ocaml/Wrapper.mli:
--------------------------------------------------------------------------------
1 | type ('a, 'b) wrapper =
2 | { wrapperA : 'a
3 | ; wrapperB : 'b
4 | ; wrapperC : string
5 | }
6 |
7 | val encodeWrapper : ('a -> Js_json.t) -> ('b -> Js_json.t) -> ('a, 'b) wrapper -> Js_json.t
8 |
9 | val decodeWrapper : (Js_json.t -> ('a, string) Belt.Result.t) -> (Js_json.t -> ('b, string) Belt.Result.t) -> Js_json.t -> (('a, 'b) wrapper, string) Belt.Result.t
10 |
--------------------------------------------------------------------------------