NickelEval.jl

Julia FFI bindings for Nickel configuration language
Log | Files | Refs | README | LICENSE

commit 0af4194c23a2b7162bea8fe8d45c955bb1f24763
parent 4aa40f21d60e64452f05a03ca94e8528e71a5927
Author: Erik Loualiche <[email protected]>
Date:   Sat,  7 Feb 2026 13:45:54 -0600

Update CLAUDE.md with comprehensive release process guidelines

- FFI artifact build and release workflow
- Artifacts.toml format specification
- Registry update procedures (Versions.toml, Deps.toml, Compat.toml)
- Version range rules and common pitfalls
- Updated architecture diagram with Artifacts.toml
- Updated API functions with native FFI methods
- Added Enum type to protocol spec and type conversion table

Co-Authored-By: Claude Opus 4.5 <[email protected]>

Diffstat:
MCLAUDE.md | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 105 insertions(+), 19 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md @@ -18,6 +18,11 @@ NickelEval/ │ └── src/lib.rs ├── deps/ │ └── build.jl # Build script for FFI +├── Artifacts.toml # Pre-built FFI library URLs/hashes +├── .github/workflows/ +│ ├── CI.yml # Julia tests +│ ├── Documentation.yml +│ └── build-ffi.yml # Cross-platform FFI builds └── test/ └── test_subprocess.jl ``` @@ -34,9 +39,10 @@ JSON.jl 1.0 provides: ### 2. Types from Nickel FFI, Not JSON The Rust FFI returns a binary protocol with native type information: -- Type tags: 0=Null, 1=Bool, 2=Int64, 3=Float64, 4=String, 5=Array, 6=Record +- Type tags: 0=Null, 1=Bool, 2=Int64, 3=Float64, 4=String, 5=Array, 6=Record, 7=Enum - Direct memory encoding without JSON serialization overhead - Preserves integer vs float distinction +- Enum variants preserved as `NickelEnum(tag, arg)` ### 3. Avoid `unwrap()` in Rust @@ -104,7 +110,50 @@ git push origin vX.Y.Z 3. Commit these changes 4. Wait for CI to pass 5. Tag the release -6. Update loulouJL registry with correct tree SHA +6. If FFI changed, build and upload new artifacts (see FFI Artifact Release below) +7. Update loulouJL registry with correct tree SHA + +### FFI Artifact Release + +When the Rust FFI code changes, new pre-built binaries must be released: + +1. **Trigger the build workflow:** + ```bash + gh workflow run build-ffi.yml --ref main + ``` + +2. **Download built artifacts** from the workflow run (4 platforms: aarch64-darwin, x86_64-darwin, x86_64-linux, x86_64-windows) + +3. **Create GitHub Release** and upload the `.tar.gz` files + +4. **Calculate tree hashes** for each artifact: + ```bash + # For each tarball: + tar -xzf libnickel_jl-PLATFORM.tar.gz + julia -e 'using Pkg; println(Pkg.GitTools.tree_hash("."))' + ``` + +5. **Update Artifacts.toml** with new SHA256 checksums and tree hashes + +### Artifacts.toml Format + +Use the `[[artifact_name]]` array format with platform properties: + +```toml +[[libnickel_jl]] +arch = "aarch64" +git-tree-sha1 = "TREE_HASH_HERE" +os = "macos" +lazy = true + + [[libnickel_jl.download]] + url = "https://github.com/LouLouLibs/NickelEval/releases/download/vX.Y.Z/libnickel_jl-aarch64-apple-darwin.tar.gz" + sha256 = "SHA256_HASH_HERE" +``` + +Platform values: +- `os`: "macos", "linux", "windows" +- `arch`: "aarch64", "x86_64" ### Documentation Requirements @@ -114,10 +163,36 @@ Any new exported function must be added to `docs/src/lib/public.md` in the appro Location: `/Users/loulou/Dropbox/projects_code/julia_packages/loulouJL/N/NickelEval/` -After tagging, update `Versions.toml` with: -```bash -git rev-parse vX.Y.Z^{tree} # Get tree SHA -``` +**Files to update:** + +1. **Versions.toml** - Add new version entry: + ```toml + ["X.Y.Z"] + git-tree-sha1 = "TREE_SHA_HERE" + ``` + Get tree SHA: `git rev-parse vX.Y.Z^{tree}` + +2. **Deps.toml** - If dependencies changed, add new version range: + ```toml + ["X.Y-0"] + Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" + LazyArtifacts = "4af54fe1-eca0-43a8-85a7-787d91b784e3" + ``` + **Important:** Version ranges must not overlap. Use `"X.Y-Z.W"` for ranges. + +3. **Compat.toml** - If compat bounds changed: + ```toml + ["X.Y-0"] + JSON = ["0.21", "1"] + ``` + Use arrays for multiple compatible versions: `["0.21", "1"]` + +**Registry format rules:** +- Section headers must be quoted: `["0.5"]` not `[0.5]` +- Version ranges: `"0.4-0.5"` (from 0.4 to 0.5), `"0.5-0"` (from 0.5 to end of 0.x) +- No spaces in ranges +- Ranges must not overlap for the same dependency ## Binary Protocol Specification @@ -132,15 +207,23 @@ The FFI uses a binary protocol for native type encoding: | 4 (String) | Tag + 4 bytes length + UTF-8 bytes | | 5 (Array) | Tag + 4 bytes count + elements | | 6 (Record) | Tag + 4 bytes field count + (key_len, key, value)* | +| 7 (Enum) | Tag + 4 bytes tag_len + tag_bytes + 1 byte has_arg + [arg_value] | ## API Functions -### Evaluation +### Evaluation (Subprocess - requires Nickel CLI) - `nickel_eval(code)` - Evaluate to `JSON.Object` - `nickel_eval(code, T)` - Evaluate and convert to type `T` - `nickel_eval_file(path)` - Evaluate a `.ncl` file -- `nickel_eval_ffi(code)` - FFI-based evaluation (faster) + +### Evaluation (Native FFI - no CLI needed) + +- `nickel_eval_ffi(code)` - FFI evaluation via JSON (supports typed parsing) +- `nickel_eval_ffi(code, T)` - FFI evaluation with type conversion +- `nickel_eval_native(code)` - FFI with binary protocol (preserves types) +- `nickel_eval_file_native(path)` - Evaluate file with import support +- `check_ffi_available()` - Check if FFI library is loaded ### Export @@ -151,15 +234,16 @@ The FFI uses a binary protocol for native type encoding: ## Type Conversion -| Nickel Type | Julia Type | -|-------------|------------| -| Null | `nothing` | -| Bool | `Bool` | -| Number (integer) | `Int64` | -| Number (float) | `Float64` | -| String | `String` | -| Array | `Vector` or `JSON.Array` | -| Record | `JSON.Object`, `Dict`, `NamedTuple`, or struct | +| Nickel Type | Julia Type (FFI native) | Julia Type (JSON) | +|-------------|-------------------------|-------------------| +| Null | `nothing` | `nothing` | +| Bool | `Bool` | `Bool` | +| Number (integer) | `Int64` | `Int64` | +| Number (float) | `Float64` | `Float64` | +| String | `String` | `String` | +| Array | `Vector{Any}` | `JSON.Array` | +| Record | `Dict{String,Any}` | `JSON.Object` | +| Enum | `NickelEnum(tag, arg)` | N/A (JSON export) | ## Nickel Language Reference @@ -191,9 +275,11 @@ let double = fun x => x * 2 in double 21 ## Dependencies ### Julia -- JSON.jl >= 1.0 +- JSON.jl >= 0.21 or >= 1.0 +- Artifacts (stdlib) +- LazyArtifacts (stdlib) -### Rust +### Rust (for building FFI locally) - nickel-lang-core = "0.9" - malachite = "0.4" - serde_json = "1.0"