@greenlabs/ppx-spice 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +232 -0
- package/CHANGELOG.md +4 -0
- package/greenlabs-ppx-spice-0.3.2.tgz +0 -0
- package/package.json +1 -1
- package/postInstall.js +3 -1
- package/ppx-linux.exe +0 -0
- package/{greenlabs-ppx-spice-0.3.1.tgz → ppx-osx-arm64.exe} +0 -0
- package/{ppx-osx.exe → ppx-osx-x64.exe} +0 -0
- package/ppx-windows.exe +0 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This document provides guidelines for AI coding agents working on the ppx_spice project.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
ppx_spice is a ReScript PPX that generates JSON (de)serializers. It is written in OCaml
|
|
8
|
+
and uses ppxlib for AST manipulation. The PPX processes ReScript type definitions annotated
|
|
9
|
+
with `@spice` and generates corresponding `_encode` and `_decode` functions.
|
|
10
|
+
|
|
11
|
+
## Build Commands
|
|
12
|
+
|
|
13
|
+
All OCaml build commands must be run from the `src/` directory:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Navigate to source directory
|
|
17
|
+
cd src
|
|
18
|
+
|
|
19
|
+
# Create opam switch (first time setup)
|
|
20
|
+
opam switch create spice 4.14.0
|
|
21
|
+
|
|
22
|
+
# Install dependencies
|
|
23
|
+
opam install . --deps-only
|
|
24
|
+
|
|
25
|
+
# Build the PPX
|
|
26
|
+
dune build
|
|
27
|
+
|
|
28
|
+
# Build with static linking (for releases)
|
|
29
|
+
dune build --profile static
|
|
30
|
+
|
|
31
|
+
# Clean build artifacts
|
|
32
|
+
dune clean
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Test Commands
|
|
36
|
+
|
|
37
|
+
Tests are written in ReScript and located in the `test/` directory:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Navigate to test directory
|
|
41
|
+
cd test
|
|
42
|
+
|
|
43
|
+
# Install dependencies
|
|
44
|
+
pnpm install
|
|
45
|
+
|
|
46
|
+
# Build ReScript code
|
|
47
|
+
pnpm res:build
|
|
48
|
+
|
|
49
|
+
# Clean and rebuild
|
|
50
|
+
pnpm res:clean && pnpm res:build
|
|
51
|
+
|
|
52
|
+
# Run all tests
|
|
53
|
+
pnpm test
|
|
54
|
+
|
|
55
|
+
# Run tests in watch mode
|
|
56
|
+
pnpm test:watch
|
|
57
|
+
|
|
58
|
+
# Run a single test file
|
|
59
|
+
pta './test/__tests__/spec/<test_name>_test.mjs' | tap-difflet
|
|
60
|
+
|
|
61
|
+
# Example: Run only records tests
|
|
62
|
+
pta './test/__tests__/spec/records_test.mjs' | tap-difflet
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Development Workflow
|
|
66
|
+
|
|
67
|
+
1. Make changes to OCaml code in `src/ppx/`
|
|
68
|
+
2. Run `dune build` in `src/`
|
|
69
|
+
3. Navigate to `test/` and run `pnpm res:clean && pnpm res:build`
|
|
70
|
+
4. Run `pnpm test` to verify changes
|
|
71
|
+
|
|
72
|
+
## Project Structure
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
ppx_spice/
|
|
76
|
+
├── src/ppx/ # OCaml PPX implementation
|
|
77
|
+
│ ├── ppx_spice.ml # Entry point, registers transformation
|
|
78
|
+
│ ├── codecs.ml # Primitive type codec generation
|
|
79
|
+
│ ├── records.ml # Record encoder/decoder generation
|
|
80
|
+
│ ├── variants.ml # Variant type handling
|
|
81
|
+
│ ├── polyvariants.ml # Polymorphic variant handling
|
|
82
|
+
│ ├── structure.ml # Implementation (.ml) processing
|
|
83
|
+
│ ├── signature.ml # Interface (.mli) processing
|
|
84
|
+
│ └── utils.ml # Shared utilities
|
|
85
|
+
├── src/bin/bin.ml # Executable entry point
|
|
86
|
+
├── test/src/ # ReScript test source types
|
|
87
|
+
└── test/test/__tests__/ # Test specifications
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### PPX Integration (rescript.json)
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"ppx-flags": ["@greenlabs/ppx-spice/ppx"],
|
|
94
|
+
"warnings": { "error": true, "number": "-48" }
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Code Style Guidelines
|
|
99
|
+
|
|
100
|
+
### OCaml Code Style
|
|
101
|
+
|
|
102
|
+
#### Formatting
|
|
103
|
+
- Use 2 spaces for indentation
|
|
104
|
+
- Use LF line endings
|
|
105
|
+
- Insert final newline at end of files
|
|
106
|
+
- Maximum line length: ~100 characters (soft limit)
|
|
107
|
+
|
|
108
|
+
#### Imports
|
|
109
|
+
Always open modules in this order at the top of each file:
|
|
110
|
+
```ocaml
|
|
111
|
+
open Ppxlib
|
|
112
|
+
open Parsetree
|
|
113
|
+
open Ast_helper
|
|
114
|
+
open Utils (* Local utilities last *)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Type Definitions
|
|
118
|
+
- Define types at the top of the module, after opens
|
|
119
|
+
- Use record types for complex data structures:
|
|
120
|
+
```ocaml
|
|
121
|
+
type parsed_decl = {
|
|
122
|
+
name : string;
|
|
123
|
+
key : expression;
|
|
124
|
+
field : expression;
|
|
125
|
+
codecs : expression option * expression option;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Naming Conventions
|
|
130
|
+
- Module names: PascalCase (`Records`, `Variants`, `Polyvariants`)
|
|
131
|
+
- Function names: snake_case (`generate_encoder`, `parse_decl`)
|
|
132
|
+
- Type names: snake_case (`parsed_decl`, `generator_settings`)
|
|
133
|
+
- Variables: snake_case (`type_name`, `param_names`)
|
|
134
|
+
- Constants/suffixes: snake_case with descriptive names
|
|
135
|
+
- `encoder_func_suffix = "_encode"`
|
|
136
|
+
- `decoder_func_suffix = "_decode"`
|
|
137
|
+
|
|
138
|
+
#### Error Handling
|
|
139
|
+
- Use `Result` type for operations that can fail
|
|
140
|
+
- Use `fail` function from `Utils` to raise location-aware errors:
|
|
141
|
+
```ocaml
|
|
142
|
+
let fail loc message = Location.raise_errorf ~loc "%s" message
|
|
143
|
+
|
|
144
|
+
(* Usage *)
|
|
145
|
+
| Ptyp_any -> fail ptyp_loc "Can't generate codecs for `any` type"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Pattern Matching
|
|
149
|
+
- Prefer exhaustive pattern matching
|
|
150
|
+
- Use `_` prefix for intentionally unused variables
|
|
151
|
+
- Group related cases together:
|
|
152
|
+
```ocaml
|
|
153
|
+
match ptype_kind with
|
|
154
|
+
| Ptype_abstract -> (* handle abstract *)
|
|
155
|
+
| Ptype_variant decls -> (* handle variant *)
|
|
156
|
+
| Ptype_record decls -> (* handle record *)
|
|
157
|
+
| _ -> fail ptype_loc "This type is not handled by spice"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### PPX-Specific Patterns
|
|
161
|
+
- Use ppxlib metaquot for AST construction: `[%expr ...]`, `[%pat? ...]`, `[%type: ...]`
|
|
162
|
+
- Always attach `res.arity` attribute for ReScript function compatibility
|
|
163
|
+
- Use `Utils.expr_func ~arity:1` for single-argument functions
|
|
164
|
+
|
|
165
|
+
### ReScript Test Code Style
|
|
166
|
+
|
|
167
|
+
#### Test Structure
|
|
168
|
+
```rescript
|
|
169
|
+
open Zora
|
|
170
|
+
|
|
171
|
+
zoraBlock("descriptive test block name", t => {
|
|
172
|
+
// Setup
|
|
173
|
+
let sampleJson = ...
|
|
174
|
+
let expected = ...
|
|
175
|
+
|
|
176
|
+
// Execute
|
|
177
|
+
let result = SomeModule.function(input)
|
|
178
|
+
|
|
179
|
+
// Assert
|
|
180
|
+
t->test("assertion description", async t => {
|
|
181
|
+
t->equal(result, expected, "message")
|
|
182
|
+
})
|
|
183
|
+
})
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### Naming
|
|
187
|
+
- Test files: `<module>_test.res` (e.g., `records_test.res`)
|
|
188
|
+
- Test blocks: Descriptive phrases in quotes
|
|
189
|
+
|
|
190
|
+
## Dependencies
|
|
191
|
+
|
|
192
|
+
### OCaml Dependencies (from opam)
|
|
193
|
+
- `ocaml` >= 4.14.0, <= 4.14.2
|
|
194
|
+
- `dune` >= 2.8
|
|
195
|
+
- `ppxlib` = 0.28.0
|
|
196
|
+
|
|
197
|
+
### ReScript Dependencies (test only)
|
|
198
|
+
- `rescript` ^12.0.0
|
|
199
|
+
- `@dusty-phillips/rescript-zora` ^4.0.0
|
|
200
|
+
|
|
201
|
+
## Common Patterns
|
|
202
|
+
|
|
203
|
+
### Generated Function Names
|
|
204
|
+
The PPX generates functions with these naming patterns:
|
|
205
|
+
- Encoder: `<type_name>_encode`
|
|
206
|
+
- Decoder: `<type_name>_decode`
|
|
207
|
+
|
|
208
|
+
### Attribute Handling
|
|
209
|
+
```ocaml
|
|
210
|
+
(* Check for attribute *)
|
|
211
|
+
match get_attribute_by_name attributes "spice.key" with
|
|
212
|
+
| Ok (Some attr) -> (* attribute present *)
|
|
213
|
+
| Ok None -> (* attribute absent *)
|
|
214
|
+
| Error s -> fail loc s
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Codec Generation Flow
|
|
218
|
+
1. `ppx_spice.ml` registers the transformation
|
|
219
|
+
2. `structure.ml` / `signature.ml` process type declarations
|
|
220
|
+
3. `codecs.ml` handles primitive types
|
|
221
|
+
4. `records.ml`, `variants.ml`, `polyvariants.ml` handle complex types
|
|
222
|
+
5. Generated AST is returned to the compiler
|
|
223
|
+
|
|
224
|
+
## CI/CD
|
|
225
|
+
|
|
226
|
+
GitHub Actions workflows are in `.github/workflows/`:
|
|
227
|
+
- `build_linux.yml` - Linux build with Alpine container
|
|
228
|
+
- `build_macos.yml` - macOS build
|
|
229
|
+
- `build_windows.yml` - Windows build
|
|
230
|
+
- `publish.yml` - NPM package publishing
|
|
231
|
+
|
|
232
|
+
Builds use OCaml 4.14.2 with static linking for portable binaries.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 0.3.2
|
|
4
|
+
|
|
5
|
+
- Fixes O(n) nested match decoder replaces O(n²) tuple pattern matching to prevent the hang with the recode with many fields https://github.com/green-labs/ppx_spice/pull/111
|
|
6
|
+
|
|
3
7
|
## 0.3.1
|
|
4
8
|
|
|
5
9
|
- Fixes [#107](https://github.com/green-labs/ppx_spice/issues/107) Arrays being reversed by Spice.arrayFromJson
|
|
Binary file
|
package/package.json
CHANGED
package/postInstall.js
CHANGED
|
@@ -38,7 +38,9 @@ switch (process.platform) {
|
|
|
38
38
|
installMacLinuxBinary("ppx-linux.exe");
|
|
39
39
|
break;
|
|
40
40
|
case "darwin":
|
|
41
|
-
|
|
41
|
+
// Detect macOS architecture: arm64 for Apple Silicon, x64 for Intel
|
|
42
|
+
const macBinary = process.arch === "arm64" ? "ppx-osx-arm64.exe" : "ppx-osx-x64.exe";
|
|
43
|
+
installMacLinuxBinary(macBinary);
|
|
42
44
|
break;
|
|
43
45
|
case "win32":
|
|
44
46
|
installWindowsBinary();
|
package/ppx-linux.exe
CHANGED
|
Binary file
|
|
index f6ea8b6..663b50e
|
|
|
Binary file
|
|
index 4639571..46e7115
|
|
|
Binary file
|
package/ppx-windows.exe
CHANGED
|
Binary file
|