feat(brahman-cards): Nickel reader + templates con merge nativo (V2)
El brazo ahora acepta `.ncl`: evalúa via nickel-lang 2.0, exporta a JSON, dispatcha por los readers JSON estándar. Templates funcionan con import + & merge nativos de Nickel — el brazo no inventa mecánica paralela. - Dep nickel-lang = "2.0.0" (interfaz estable). - Nuevo módulo nickel_eval con eval_nickel_file(path) -> Value y errores tipados (Io/Eval/Export/JsonReparse). Mensaje de Nickel como texto plano sin ANSI. - load_card_with añade arm "ncl" simétrico al "json". - CardLoadError::Nickel propaga el error limpio. - Imports resueltos: parent dir del input + env BRAHMAN_CARDS_TEMPLATES_DIR (registry global, opcional). - Convención obligatoria documentada: fields override-ables del template usan `| default` (sin eso Nickel rechaza el merge). 9 tests nuevos: eval directo, dispatch a UiModule/Ente, template merge con id+label override, registry via env, error wrapping, contract violation en eval-time (`id | String = 42`), shape desconocida. 22 tests totales en brahman-cards (13 JSON V1 + 9 Nickel V2). Workspace build verde. NO hace: migrar consumers, set canonical de templates, KCL→Nickel — todos para commits siguientes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,101 @@ ratio/diff ver `git show <sha>`.
|
|||||||
|
|
||||||
## 2026-05-09
|
## 2026-05-09
|
||||||
|
|
||||||
|
### feat(brahman-cards): Nickel reader + templates con merge nativo (V2)
|
||||||
|
Sigue al V1 (readers JSON). Ahora el brazo acepta inputs `.ncl`:
|
||||||
|
los evalúa via `nickel-lang` 2.0, exporta a JSON, y dispatcha por
|
||||||
|
los mismos readers JSON estándar. Un `.ncl` puede producir
|
||||||
|
cualquier `CardBody` siempre que su shape sea reconocida. Los
|
||||||
|
templates funcionan con los `import` + `&` merge nativos de
|
||||||
|
Nickel — el brazo no inventa una mecánica paralela.
|
||||||
|
|
||||||
|
Cambios:
|
||||||
|
- **Dep `nickel-lang = "2.0.0"`** (interfaz estable, no
|
||||||
|
`nickel-lang-core` que es internal/inestable). Compila clean
|
||||||
|
pero suma ~1 min al build cold del crate.
|
||||||
|
- **Nuevo módulo `nickel_eval.rs`** con `eval_nickel_file(path) ->
|
||||||
|
Result<Value, NickelEvalError>`. Errores tipados:
|
||||||
|
`Io`, `Eval`, `Export`, `JsonReparse` — el mensaje de Nickel se
|
||||||
|
formatea como texto plano (sin ANSI) para que sea legible en
|
||||||
|
logs y toasts.
|
||||||
|
- **`load_card_with` añade `"ncl"`**: lee archivo → eval Nickel →
|
||||||
|
exporta a JSON → parsea de vuelta a Value → dispatch a los
|
||||||
|
readers JSON. Pipeline simétrico a `"json"`.
|
||||||
|
- **`CardLoadError::Nickel(NickelEvalError)`**: el error de
|
||||||
|
Nickel se propaga limpio al error público del brazo.
|
||||||
|
- **Resolución de imports**:
|
||||||
|
- El parent dir del input se agrega como import path → `import
|
||||||
|
"./template.ncl"` resuelve sin config.
|
||||||
|
- El env `BRAHMAN_CARDS_TEMPLATES_DIR` (constante exportada
|
||||||
|
`BRAHMAN_CARDS_TEMPLATES_ENV`) agrega un registry global →
|
||||||
|
`import "ui_module_minimal.ncl"` desde cualquier ubicación.
|
||||||
|
- No hay magic resolución por kind. El autor del Card decide
|
||||||
|
qué template importa.
|
||||||
|
|
||||||
|
**Convención obligatoria de templates** (documentada en
|
||||||
|
`nickel_eval.rs`): las fields que el usuario va a sobrescribir
|
||||||
|
deben marcarse `| default` (o `| optional`). Sin ese marker
|
||||||
|
Nickel rechaza el merge de strings/numbers no-iguales con la
|
||||||
|
misma prioridad. Patrón canónico:
|
||||||
|
|
||||||
|
```nickel
|
||||||
|
# template ui_module_basic.ncl
|
||||||
|
{
|
||||||
|
id | String | default = "TEMPLATE_ID",
|
||||||
|
label | String | default = "TEMPLATE_LABEL",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
# uso concreto
|
||||||
|
let base = import "ui_module_basic.ncl" in
|
||||||
|
base & { id = "my_id", label = "Mi Label" }
|
||||||
|
```
|
||||||
|
|
||||||
|
9 tests nuevos en `tests/nickel.rs`:
|
||||||
|
- `eval_nickel_file_returns_value_for_valid_input` — happy path.
|
||||||
|
- `eval_nickel_file_surfaces_evaluation_error` — variant `Eval`
|
||||||
|
con path + message.
|
||||||
|
- `load_card_dispatches_ncl_to_ui_module_variant` — pipeline
|
||||||
|
e2e a UiModule.
|
||||||
|
- `load_card_dispatches_ncl_to_ente_variant` — pipeline e2e a
|
||||||
|
Ente.
|
||||||
|
- `template_merge_overrides_id_and_label_only` — el caso del
|
||||||
|
user: template + override de id+label, resto del template
|
||||||
|
intacto.
|
||||||
|
- `template_resolves_via_env_registry` — uso del env como
|
||||||
|
registry global.
|
||||||
|
- `load_card_wraps_nickel_error_in_card_load_error` — wrap
|
||||||
|
limpio del error.
|
||||||
|
- `nickel_contract_violation_caught_at_eval_time` — value-add
|
||||||
|
concreto: `id | String = 42` falla en eval, no en deserialize
|
||||||
|
ni aguas abajo.
|
||||||
|
- `ncl_evaluating_to_unknown_shape_returns_no_matching_reader`
|
||||||
|
— sanity de coherencia con dispatcher JSON.
|
||||||
|
|
||||||
|
22 tests en total en `brahman-cards` (13 JSON V1 + 9 Nickel V2).
|
||||||
|
Workspace build verde tras la dep nueva.
|
||||||
|
|
||||||
|
**Lo que NO hace V2** (sigue pendiente):
|
||||||
|
- No migra consumers — `nakui-ui` sigue cargando con
|
||||||
|
`nakui_ui_schema::load_modules_from_dir`. La migración a
|
||||||
|
`brahman_cards::load_card` queda para después.
|
||||||
|
- No define un set canonical de templates en el repo (algo
|
||||||
|
como `templates/ente_basic.ncl`, `templates/ui_module_minimal.ncl`).
|
||||||
|
Eso emerge cuando aparezcan los primeros casos de uso reales
|
||||||
|
donde dos cards comparten estructura.
|
||||||
|
- No hace cross-validation entre template + override (ej:
|
||||||
|
detectar que un override saca un campo required del template).
|
||||||
|
Nickel ya lo hace via contracts si el template tiene un schema.
|
||||||
|
- No expone una API streaming (load N cards en paralelo). El
|
||||||
|
use case actual es one-shot al boot.
|
||||||
|
|
||||||
|
**Pendientes para próximos commits** (orden):
|
||||||
|
1. Migrar consumers (`nakui-ui` consume `brahman_cards::load_card`).
|
||||||
|
2. Yahweh refactor: lift del MetaUi runtime a `crates/modules/ui_engine/`.
|
||||||
|
3. KCL → Nickel: kcl_wrapper reemplazado por evaluación de Nickel
|
||||||
|
contracts; los 3 schemas .k de nakui modules pasan a .ncl.
|
||||||
|
4. card.k eliminado (es REFERENCE ONLY documentado).
|
||||||
|
|
||||||
### feat(brahman-cards): brazo unificado V1 — readers JSON + estructura canónica
|
### feat(brahman-cards): brazo unificado V1 — readers JSON + estructura canónica
|
||||||
**Pivote arquitectónico** decidido en charla: Brahman maneja varios
|
**Pivote arquitectónico** decidido en charla: Brahman maneja varios
|
||||||
formatos legítimos de "Card" (cada formato vive en su crate origen y
|
formatos legítimos de "Card" (cada formato vive en su crate origen y
|
||||||
|
|||||||
Generated
+562
-26
@@ -106,6 +106,12 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aliasable"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aligned"
|
name = "aligned"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@@ -270,12 +276,24 @@ dependencies = [
|
|||||||
"password-hash",
|
"password-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arraydeque"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
|
checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
@@ -315,7 +333,16 @@ version = "3.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
|
checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"term",
|
"term 0.7.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ascii-canvas"
|
||||||
|
version = "4.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891"
|
||||||
|
dependencies = [
|
||||||
|
"term 1.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -800,7 +827,7 @@ dependencies = [
|
|||||||
"aligned",
|
"aligned",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arg_enum_proc_macro",
|
"arg_enum_proc_macro",
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"log",
|
"log",
|
||||||
"num-rational",
|
"num-rational",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -818,7 +845,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
|
checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"log",
|
"log",
|
||||||
"nom 8.0.0",
|
"nom 8.0.0",
|
||||||
"num-rational",
|
"num-rational",
|
||||||
@@ -831,7 +858,7 @@ version = "0.8.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38"
|
checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -887,6 +914,12 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "beef"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "1.3.3"
|
version = "1.3.3"
|
||||||
@@ -964,6 +997,12 @@ version = "2.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitmaps"
|
||||||
|
version = "3.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1d084b0137aaa901caf9f1e8b21daa6aa24d41cd806e111335541eff9683bd6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitstream-io"
|
name = "bitstream-io"
|
||||||
version = "4.10.0"
|
version = "4.10.0"
|
||||||
@@ -995,7 +1034,7 @@ dependencies = [
|
|||||||
"ash-window",
|
"ash-window",
|
||||||
"bitflags 2.11.1",
|
"bitflags 2.11.1",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"codespan-reporting",
|
"codespan-reporting 0.12.0",
|
||||||
"glow",
|
"glow",
|
||||||
"gpu-alloc",
|
"gpu-alloc",
|
||||||
"gpu-alloc-ash",
|
"gpu-alloc-ash",
|
||||||
@@ -1059,7 +1098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce"
|
checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"constant_time_eq",
|
"constant_time_eq",
|
||||||
@@ -1200,6 +1239,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"brahman-card",
|
"brahman-card",
|
||||||
"nakui-ui-schema",
|
"nakui-ui-schema",
|
||||||
|
"nickel-lang",
|
||||||
"nouser-card",
|
"nouser-card",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -1432,7 +1472,7 @@ dependencies = [
|
|||||||
"cedar-policy-core",
|
"cedar-policy-core",
|
||||||
"cedar-policy-validator",
|
"cedar-policy-validator",
|
||||||
"itertools 0.10.5",
|
"itertools 0.10.5",
|
||||||
"lalrpop-util",
|
"lalrpop-util 0.20.2",
|
||||||
"ref-cast",
|
"ref-cast",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -1449,8 +1489,8 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"itertools 0.10.5",
|
"itertools 0.10.5",
|
||||||
"lalrpop",
|
"lalrpop 0.20.2",
|
||||||
"lalrpop-util",
|
"lalrpop-util 0.20.2",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"miette",
|
"miette",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -1706,6 +1746,16 @@ dependencies = [
|
|||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "codespan"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "583f52b0658b321b25fd6b209b6c76cf058f433071297de64e5980c3d9aad937"
|
||||||
|
dependencies = [
|
||||||
|
"codespan-reporting 0.13.1",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
@@ -1717,6 +1767,17 @@ dependencies = [
|
|||||||
"unicode-width 0.2.2",
|
"unicode-width 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "codespan-reporting"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"termcolor",
|
||||||
|
"unicode-width 0.2.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -3264,6 +3325,12 @@ version = "0.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.1.9"
|
version = "1.1.9"
|
||||||
@@ -4053,7 +4120,7 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4f3bedd573fafafa13d1200b356c588cf094fb2786e3684bb3f5ea59b549fa9"
|
checksum = "e4f3bedd573fafafa13d1200b356c588cf094fb2786e3684bb3f5ea59b549fa9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"log",
|
"log",
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
@@ -4773,6 +4840,15 @@ version = "0.13.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"
|
checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "imbl-sized-chunks"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f4241005618a62f8d57b2febd02510fb96e0137304728543dfc5fd6f052c22d"
|
||||||
|
dependencies = [
|
||||||
|
"bitmaps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "imgref"
|
name = "imgref"
|
||||||
version = "1.12.1"
|
version = "1.12.1"
|
||||||
@@ -4815,6 +4891,15 @@ dependencies = [
|
|||||||
"web-time",
|
"web-time",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indoc"
|
||||||
|
version = "2.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
|
||||||
|
dependencies = [
|
||||||
|
"rustversion",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inotify"
|
name = "inotify"
|
||||||
version = "0.9.6"
|
version = "0.9.6"
|
||||||
@@ -4994,6 +5079,15 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "json_scanner"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe0a2dc336065c75719cffd3c6c929e0ec4ed85b92b8248a7bbd999acb0e419c"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonwebtoken"
|
name = "jsonwebtoken"
|
||||||
version = "9.3.1"
|
version = "9.3.1"
|
||||||
@@ -5009,6 +5103,15 @@ dependencies = [
|
|||||||
"simple_asn1",
|
"simple_asn1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keccak"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653"
|
||||||
|
dependencies = [
|
||||||
|
"cpufeatures 0.2.17",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "khronos-egl"
|
name = "khronos-egl"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
@@ -5045,7 +5148,7 @@ version = "0.11.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62"
|
checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"euclid",
|
"euclid",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
@@ -5065,22 +5168,44 @@ version = "0.20.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca"
|
checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ascii-canvas",
|
"ascii-canvas 3.0.0",
|
||||||
"bit-set 0.5.3",
|
"bit-set 0.5.3",
|
||||||
"ena",
|
"ena",
|
||||||
"itertools 0.11.0",
|
"itertools 0.11.0",
|
||||||
"lalrpop-util",
|
"lalrpop-util 0.20.2",
|
||||||
"petgraph",
|
"petgraph 0.6.5",
|
||||||
"pico-args",
|
"pico-args",
|
||||||
"regex",
|
"regex",
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
"string_cache",
|
"string_cache",
|
||||||
"term",
|
"term 0.7.0",
|
||||||
"tiny-keccak",
|
"tiny-keccak",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lalrpop"
|
||||||
|
version = "0.22.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501"
|
||||||
|
dependencies = [
|
||||||
|
"ascii-canvas 4.0.0",
|
||||||
|
"bit-set 0.8.0",
|
||||||
|
"ena",
|
||||||
|
"itertools 0.14.0",
|
||||||
|
"lalrpop-util 0.22.2",
|
||||||
|
"petgraph 0.7.1",
|
||||||
|
"pico-args",
|
||||||
|
"regex",
|
||||||
|
"regex-syntax",
|
||||||
|
"sha3",
|
||||||
|
"string_cache",
|
||||||
|
"term 1.2.1",
|
||||||
|
"unicode-xid",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lalrpop-util"
|
name = "lalrpop-util"
|
||||||
version = "0.20.2"
|
version = "0.20.2"
|
||||||
@@ -5090,6 +5215,16 @@ dependencies = [
|
|||||||
"regex-automata",
|
"regex-automata",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lalrpop-util"
|
||||||
|
version = "0.22.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
"rustversion",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -5593,6 +5728,40 @@ dependencies = [
|
|||||||
"value-bag",
|
"value-bag",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logos"
|
||||||
|
version = "0.15.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff472f899b4ec2d99161c51f60ff7075eeb3097069a36050d8037a6325eb8154"
|
||||||
|
dependencies = [
|
||||||
|
"logos-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logos-codegen"
|
||||||
|
version = "0.15.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "192a3a2b90b0c05b27a0b2c43eecdb7c415e29243acc3f89cc8247a5b693045c"
|
||||||
|
dependencies = [
|
||||||
|
"beef",
|
||||||
|
"fnv",
|
||||||
|
"lazy_static",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex-syntax",
|
||||||
|
"rustc_version",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logos-derive"
|
||||||
|
version = "0.15.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "605d9697bcd5ef3a42d38efc51541aa3d6a4a25f7ab6d1ed0da5ac632a26b470"
|
||||||
|
dependencies = [
|
||||||
|
"logos-codegen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "loop9"
|
name = "loop9"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -5643,7 +5812,7 @@ version = "1.0.19"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4336502e29e32af93cf2dad2214ed6003c17ceb5bd499df77b1de663b9042b92"
|
checksum = "4336502e29e32af93cf2dad2214ed6003c17ceb5bd499df77b1de663b9042b92"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"euclid",
|
"euclid",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
@@ -5691,6 +5860,68 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
|
checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "malachite"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec410515e231332b14cd986a475d1c3323bcfa4c7efc038bfa1d5b410b1c57e4"
|
||||||
|
dependencies = [
|
||||||
|
"malachite-base",
|
||||||
|
"malachite-float",
|
||||||
|
"malachite-nz",
|
||||||
|
"malachite-q",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "malachite-base"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c738d3789301e957a8f7519318fcbb1b92bb95863b28f6938ae5a05be6259f34"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown 0.15.5",
|
||||||
|
"itertools 0.14.0",
|
||||||
|
"libm",
|
||||||
|
"ryu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "malachite-float"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9446a966be7f1708c10badd6690d3094b5ad62d3accdcf2154740656d7650cfa"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.14.0",
|
||||||
|
"malachite-base",
|
||||||
|
"malachite-nz",
|
||||||
|
"malachite-q",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "malachite-nz"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1707c9a1fa36ce21749b35972bfad17bbf34cf5a7c96897c0491da321e387d3b"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.14.0",
|
||||||
|
"libm",
|
||||||
|
"malachite-base",
|
||||||
|
"serde",
|
||||||
|
"wide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "malachite-q"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d764801aa4e96bbb69b389dcd03b50075345131cd63ca2e380bca71cc37a3675"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.14.0",
|
||||||
|
"malachite-base",
|
||||||
|
"malachite-nz",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "malloc_buf"
|
name = "malloc_buf"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
@@ -6110,11 +6341,11 @@ version = "25.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b977c445f26e49757f9aca3631c3b8b836942cb278d69a92e7b80d3b24da632"
|
checksum = "2b977c445f26e49757f9aca3631c3b8b836942cb278d69a92e7b80d3b24da632"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"bit-set 0.8.0",
|
"bit-set 0.8.0",
|
||||||
"bitflags 2.11.1",
|
"bitflags 2.11.1",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"codespan-reporting",
|
"codespan-reporting 0.12.0",
|
||||||
"half",
|
"half",
|
||||||
"hashbrown 0.15.5",
|
"hashbrown 0.15.5",
|
||||||
"hexf-parse",
|
"hexf-parse",
|
||||||
@@ -6135,7 +6366,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"brahman-card",
|
"brahman-card",
|
||||||
"brahman-sidecar",
|
"brahman-sidecar",
|
||||||
"petgraph",
|
"petgraph 0.6.5",
|
||||||
"rhai",
|
"rhai",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -6315,6 +6546,102 @@ dependencies = [
|
|||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nickel-lang"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec629a17e21b7e192dfc715a9567fb4f773a6d0c92424f0ec659c6633f31b087"
|
||||||
|
dependencies = [
|
||||||
|
"codespan-reporting 0.13.1",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"malachite",
|
||||||
|
"nickel-lang-core",
|
||||||
|
"nickel-lang-vector",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
|
"toml 0.9.12+spec-1.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nickel-lang-core"
|
||||||
|
version = "0.16.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51647f09e6e385c140226867c62292f23c31241ee2b4986f3f71a40d48e88a60"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.22.1",
|
||||||
|
"bumpalo",
|
||||||
|
"codespan",
|
||||||
|
"codespan-reporting 0.13.1",
|
||||||
|
"colorchoice",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"indoc",
|
||||||
|
"json_scanner",
|
||||||
|
"lalrpop 0.22.2",
|
||||||
|
"lalrpop-util 0.22.2",
|
||||||
|
"logos",
|
||||||
|
"malachite",
|
||||||
|
"malachite-q",
|
||||||
|
"md-5",
|
||||||
|
"nickel-lang-parser",
|
||||||
|
"nickel-lang-vector",
|
||||||
|
"once_cell",
|
||||||
|
"ouroboros",
|
||||||
|
"paste",
|
||||||
|
"pretty",
|
||||||
|
"regex",
|
||||||
|
"saphyr-parser",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
|
"sha-1",
|
||||||
|
"sha2",
|
||||||
|
"simple-counter",
|
||||||
|
"smallvec",
|
||||||
|
"strip-ansi-escapes",
|
||||||
|
"strsim",
|
||||||
|
"toml 0.9.12+spec-1.1.0",
|
||||||
|
"toml_edit 0.23.10+spec-1.0.0",
|
||||||
|
"typed-arena",
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nickel-lang-parser"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20d8810705f1a243b1996c83fe9f173d8fb33f1cc97ea5ff7486cc6ef8981f81"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"codespan",
|
||||||
|
"codespan-reporting 0.13.1",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"lalrpop 0.22.2",
|
||||||
|
"lalrpop-util 0.22.2",
|
||||||
|
"logos",
|
||||||
|
"malachite",
|
||||||
|
"nickel-lang-vector",
|
||||||
|
"ouroboros",
|
||||||
|
"pretty",
|
||||||
|
"regex",
|
||||||
|
"saphyr-parser",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"simple-counter",
|
||||||
|
"toml_edit 0.23.10+spec-1.0.0",
|
||||||
|
"typed-arena",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nickel-lang-vector"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "870c323d81061fc47db4aa7346f6f3492f3e4bb8bd5dd8b7c85ac9d0c9709f0c"
|
||||||
|
dependencies = [
|
||||||
|
"imbl-sized-chunks",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.29.0"
|
version = "0.29.0"
|
||||||
@@ -6989,6 +7316,30 @@ dependencies = [
|
|||||||
"ureq",
|
"ureq",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ouroboros"
|
||||||
|
version = "0.18.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59"
|
||||||
|
dependencies = [
|
||||||
|
"aliasable",
|
||||||
|
"ouroboros_macro",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ouroboros_macro"
|
||||||
|
version = "0.18.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.4.1",
|
||||||
|
"proc-macro2",
|
||||||
|
"proc-macro2-diagnostics",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking"
|
name = "parking"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
@@ -7147,7 +7498,17 @@ version = "0.6.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fixedbitset",
|
"fixedbitset 0.4.2",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset 0.5.7",
|
||||||
"indexmap 2.14.0",
|
"indexmap 2.14.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -7430,6 +7791,17 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty"
|
||||||
|
version = "0.12.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d22152487193190344590e4f30e219cf3fe140d9e7a3fdb683d82aa2c5f4156"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec 0.5.2",
|
||||||
|
"typed-arena",
|
||||||
|
"unicode-width 0.2.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.37"
|
version = "0.2.37"
|
||||||
@@ -7480,6 +7852,19 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2-diagnostics"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
"version_check",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "profiling"
|
name = "profiling"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
@@ -7811,7 +8196,7 @@ dependencies = [
|
|||||||
"aligned-vec",
|
"aligned-vec",
|
||||||
"arbitrary",
|
"arbitrary",
|
||||||
"arg_enum_proc_macro",
|
"arg_enum_proc_macro",
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"av-scenechange",
|
"av-scenechange",
|
||||||
"av1-grain",
|
"av1-grain",
|
||||||
"bitstream-io",
|
"bitstream-io",
|
||||||
@@ -8449,7 +8834,7 @@ version = "1.42.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c5108e3d4d903e21aac27f12ba5377b6b34f9f44b325e4894c7924169d06995"
|
checksum = "0c5108e3d4d903e21aac27f12ba5377b6b34f9f44b325e4894c7924169d06995"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"borsh",
|
"borsh",
|
||||||
"bytes",
|
"bytes",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -8640,6 +9025,15 @@ version = "1.0.23"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "safe_arch"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "salsa20"
|
name = "salsa20"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@@ -8658,6 +9052,16 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "saphyr-parser"
|
||||||
|
version = "0.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fb771b59f6b1985d1406325ec28f97cfb14256abcec4fdfb37b36a1766d6af7"
|
||||||
|
dependencies = [
|
||||||
|
"arraydeque",
|
||||||
|
"hashlink 0.10.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schannel"
|
name = "schannel"
|
||||||
version = "0.1.29"
|
version = "0.1.29"
|
||||||
@@ -8970,6 +9374,30 @@ dependencies = [
|
|||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_yaml"
|
||||||
|
version = "0.9.34+deprecated"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"unsafe-libyaml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha-1"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures 0.2.17",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.10.6"
|
version = "0.10.6"
|
||||||
@@ -8998,6 +9426,16 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha3"
|
||||||
|
version = "0.10.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"keccak",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@@ -9053,6 +9491,12 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simple-counter"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bb57743b52ea059937169c0061d70298fe2df1d2c988b44caae79dd979d9b49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simple_asn1"
|
name = "simple_asn1"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
@@ -9388,6 +9832,15 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strip-ansi-escapes"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025"
|
||||||
|
dependencies = [
|
||||||
|
"vte",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -9449,7 +9902,7 @@ version = "2.6.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3429154a8b5a98ca39100ba45ef49ae046fb1d0869dff78d78a2670b1b278982"
|
checksum = "3429154a8b5a98ca39100ba45ef49ae046fb1d0869dff78d78a2670b1b278982"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"async-channel 2.5.0",
|
"async-channel 2.5.0",
|
||||||
"bincode",
|
"bincode",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -9814,7 +10267,7 @@ version = "0.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a13e5d13f79d558b5d353a98072ca8ca0e99da429467804de959aa8c83c9a004"
|
checksum = "a13e5d13f79d558b5d353a98072ca8ca0e99da429467804de959aa8c83c9a004"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"grid",
|
"grid",
|
||||||
"serde",
|
"serde",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
@@ -9896,6 +10349,15 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "term"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@@ -10024,7 +10486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
|
checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"log",
|
"log",
|
||||||
@@ -10188,6 +10650,21 @@ dependencies = [
|
|||||||
"toml_edit 0.22.27",
|
"toml_edit 0.22.27",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.9.12+spec-1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"serde_core",
|
||||||
|
"serde_spanned 1.1.1",
|
||||||
|
"toml_datetime 0.7.5+spec-1.1.0",
|
||||||
|
"toml_parser",
|
||||||
|
"toml_writer",
|
||||||
|
"winnow 0.7.15",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "1.1.2+spec-1.1.0"
|
version = "1.1.2+spec-1.1.0"
|
||||||
@@ -10212,6 +10689,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.7.5+spec-1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "1.1.1+spec-1.1.0"
|
version = "1.1.1+spec-1.1.0"
|
||||||
@@ -10235,6 +10721,19 @@ dependencies = [
|
|||||||
"winnow 0.7.15",
|
"winnow 0.7.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.23.10+spec-1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"toml_datetime 0.7.5+spec-1.1.0",
|
||||||
|
"toml_parser",
|
||||||
|
"toml_writer",
|
||||||
|
"winnow 0.7.15",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.25.11+spec-1.1.0"
|
version = "0.25.11+spec-1.1.0"
|
||||||
@@ -10481,6 +10980,12 @@ dependencies = [
|
|||||||
"core_maths",
|
"core_maths",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typed-arena"
|
||||||
|
version = "2.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typeid"
|
name = "typeid"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@@ -10667,6 +11172,12 @@ dependencies = [
|
|||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsafe-libyaml"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unsigned-varint"
|
name = "unsigned-varint"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
@@ -10879,6 +11390,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vte"
|
||||||
|
version = "0.14.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "waker-fn"
|
name = "waker-fn"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@@ -11035,7 +11555,7 @@ version = "0.40.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a19af97fcb96045dd1d6b4d23e2b4abdbbe81723dbc5c9f016eb52145b320063"
|
checksum = "a19af97fcb96045dd1d6b4d23e2b4abdbbe81723dbc5c9f016eb52145b320063"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec 0.7.6",
|
||||||
"multi-stash",
|
"multi-stash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"spin",
|
"spin",
|
||||||
@@ -11317,6 +11837,16 @@ dependencies = [
|
|||||||
"winsafe",
|
"winsafe",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wide"
|
||||||
|
version = "0.7.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"safe_arch",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "widestring"
|
name = "widestring"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@@ -12461,6 +12991,12 @@ dependencies = [
|
|||||||
"web-time",
|
"web-time",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yasna"
|
name = "yasna"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ ulid = { workspace = true }
|
|||||||
brahman-card = { path = "../brahman-card" }
|
brahman-card = { path = "../brahman-card" }
|
||||||
nouser-card = { path = "../../modules/nouser/card" }
|
nouser-card = { path = "../../modules/nouser/card" }
|
||||||
nakui-ui-schema = { path = "../../modules/nakui/ui-schema" }
|
nakui-ui-schema = { path = "../../modules/nakui/ui-schema" }
|
||||||
|
nickel-lang = "2.0.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|||||||
@@ -157,6 +157,9 @@ pub enum CardLoadError {
|
|||||||
ext: String,
|
ext: String,
|
||||||
supported: Vec<&'static str>,
|
supported: Vec<&'static str>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error("evaluación Nickel: {0}")]
|
||||||
|
Nickel(#[from] NickelEvalError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait de reader. Cada formato implementa una instancia.
|
/// Trait de reader. Cada formato implementa una instancia.
|
||||||
@@ -180,7 +183,9 @@ pub trait CardReader: Send + Sync {
|
|||||||
fn read(&self, input: Value) -> Result<Card, CardLoadError>;
|
fn read(&self, input: Value) -> Result<Card, CardLoadError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod nickel_eval;
|
||||||
mod readers;
|
mod readers;
|
||||||
|
pub use nickel_eval::{eval_nickel_file, NickelEvalError, BRAHMAN_CARDS_TEMPLATES_ENV};
|
||||||
pub use readers::{EnteJsonReader, MonadJsonReader, UiModuleJsonReader};
|
pub use readers::{EnteJsonReader, MonadJsonReader, UiModuleJsonReader};
|
||||||
|
|
||||||
/// Construye el set default de readers para inputs JSON. El orden
|
/// Construye el set default de readers para inputs JSON. El orden
|
||||||
@@ -222,9 +227,18 @@ pub fn load_card_with(
|
|||||||
let value: Value = serde_json::from_slice(&bytes)?;
|
let value: Value = serde_json::from_slice(&bytes)?;
|
||||||
dispatch_to_reader(value, readers)
|
dispatch_to_reader(value, readers)
|
||||||
}
|
}
|
||||||
|
"ncl" => {
|
||||||
|
// Nickel pipeline: leer archivo → evaluar deeply → exportar
|
||||||
|
// a JSON → parsear como Value → dispatch a los readers JSON
|
||||||
|
// estándar. Templates funcionan via los `import` nativos de
|
||||||
|
// Nickel; el evaluator resuelve relativo al input y al
|
||||||
|
// `BRAHMAN_CARDS_TEMPLATES_DIR` env (si está set).
|
||||||
|
let value = eval_nickel_file(path)?;
|
||||||
|
dispatch_to_reader(value, readers)
|
||||||
|
}
|
||||||
other => Err(CardLoadError::UnsupportedExtension {
|
other => Err(CardLoadError::UnsupportedExtension {
|
||||||
ext: other.to_string(),
|
ext: other.to_string(),
|
||||||
supported: vec!["json"],
|
supported: vec!["json", "ncl"],
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
//! Evaluador Nickel para inputs `.ncl`.
|
||||||
|
//!
|
||||||
|
//! El brazo de Cards lee Nickel como **fuente** y produce JSON como
|
||||||
|
//! **representación intermedia** que después dispatcha por los readers
|
||||||
|
//! estándar. Esto significa que un `.ncl` puede producir cualquier
|
||||||
|
//! variant del [`super::CardBody`] siempre que evalúe a una shape JSON
|
||||||
|
//! que alguno de los readers reconozca.
|
||||||
|
//!
|
||||||
|
//! # Templates
|
||||||
|
//!
|
||||||
|
//! Nickel soporta `import "..."` y el operador `&` de merge nativo. Un
|
||||||
|
//! Card "concreto" puede ser un template + override:
|
||||||
|
//!
|
||||||
|
//! ```nickel
|
||||||
|
//! let base = import "ente_basic.ncl" in
|
||||||
|
//! base & { id = "01ARZ...", label = "mi-ente" }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! **Convención obligatoria del template**: las fields que el usuario
|
||||||
|
//! va a sobrescribir tienen que estar marcadas `| default` (o
|
||||||
|
//! `| optional`). Nickel rechaza el merge de dos strings/numbers
|
||||||
|
//! distintos con la misma prioridad — el `| default` baja la prioridad
|
||||||
|
//! del template y deja que el override del user gane:
|
||||||
|
//!
|
||||||
|
//! ```nickel
|
||||||
|
//! # template ui_module_basic.ncl
|
||||||
|
//! {
|
||||||
|
//! id | String | default = "TEMPLATE_ID",
|
||||||
|
//! label | String | default = "TEMPLATE_LABEL",
|
||||||
|
//! # ...
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Resolución de imports (en orden):
|
||||||
|
//! 1. Relativo al directorio del archivo input (default de Nickel).
|
||||||
|
//! 2. `BRAHMAN_CARDS_TEMPLATES_DIR` (env). Permite tener un
|
||||||
|
//! registry global de templates accesible por nombre desnudo:
|
||||||
|
//! `import "ui_module_basic.ncl"`.
|
||||||
|
//!
|
||||||
|
//! No agregamos magic resolución por kind — el autor decide qué
|
||||||
|
//! template importa explícitamente.
|
||||||
|
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use serde_json::Value;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Variable de entorno opcional. Si está set, su path se agrega al
|
||||||
|
/// search path de imports de Nickel después del parent dir del input,
|
||||||
|
/// permitiendo `import "<nombre>.ncl"` desde cualquier ubicación.
|
||||||
|
pub const BRAHMAN_CARDS_TEMPLATES_ENV: &str = "BRAHMAN_CARDS_TEMPLATES_DIR";
|
||||||
|
|
||||||
|
/// Errores específicos del pipeline Nickel. Wrap del error de Nickel
|
||||||
|
/// formateado como texto plano (sin ANSI) + el path del input para
|
||||||
|
/// contexto.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum NickelEvalError {
|
||||||
|
#[error("io leyendo {path}: {source}")]
|
||||||
|
Io {
|
||||||
|
path: String,
|
||||||
|
#[source]
|
||||||
|
source: std::io::Error,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[error("evaluación de '{path}' falló:\n{message}")]
|
||||||
|
Eval { path: String, message: String },
|
||||||
|
|
||||||
|
#[error("export a JSON de '{path}' falló:\n{message}")]
|
||||||
|
Export { path: String, message: String },
|
||||||
|
|
||||||
|
#[error("JSON exportado por Nickel no parsea de vuelta: {source}")]
|
||||||
|
JsonReparse {
|
||||||
|
#[source]
|
||||||
|
source: serde_json::Error,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lee `path` (debe ser un `.ncl` válido), lo evalúa profundamente vía
|
||||||
|
/// `nickel-lang` y devuelve el resultado como `serde_json::Value`
|
||||||
|
/// listo para dispatch a un reader JSON.
|
||||||
|
///
|
||||||
|
/// El parent dir del input se agrega como import path para que
|
||||||
|
/// imports relativos tipo `import "./template.ncl"` funcionen sin
|
||||||
|
/// configuración extra. Si `BRAHMAN_CARDS_TEMPLATES_DIR` está set,
|
||||||
|
/// también se agrega.
|
||||||
|
pub fn eval_nickel_file(path: &Path) -> Result<Value, NickelEvalError> {
|
||||||
|
let path_display = path.display().to_string();
|
||||||
|
let source = std::fs::read_to_string(path).map_err(|e| NickelEvalError::Io {
|
||||||
|
path: path_display.clone(),
|
||||||
|
source: e,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut import_paths: Vec<OsString> = Vec::new();
|
||||||
|
if let Some(parent) = path.parent() {
|
||||||
|
if !parent.as_os_str().is_empty() {
|
||||||
|
import_paths.push(parent.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Ok(reg) = std::env::var(BRAHMAN_CARDS_TEMPLATES_ENV) {
|
||||||
|
if !reg.is_empty() {
|
||||||
|
import_paths.push(reg.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ctx = nickel_lang::Context::new()
|
||||||
|
.with_added_import_paths(import_paths)
|
||||||
|
.with_source_name(path_display.clone());
|
||||||
|
|
||||||
|
let expr = ctx
|
||||||
|
.eval_deep_for_export(&source)
|
||||||
|
.map_err(|e| NickelEvalError::Eval {
|
||||||
|
path: path_display.clone(),
|
||||||
|
message: format_nickel_error(&e),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let json_str = ctx
|
||||||
|
.expr_to_json(&expr)
|
||||||
|
.map_err(|e| NickelEvalError::Export {
|
||||||
|
path: path_display.clone(),
|
||||||
|
message: format_nickel_error(&e),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
serde_json::from_str(&json_str).map_err(|e| NickelEvalError::JsonReparse { source: e })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formatea un error de Nickel como texto plano. Usa `ErrorFormat::Text`
|
||||||
|
/// (sin ANSI) para que sea legible en logs y mensajes de UI sin
|
||||||
|
/// escape sequences.
|
||||||
|
fn format_nickel_error(err: &nickel_lang::Error) -> String {
|
||||||
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
|
if err
|
||||||
|
.format(&mut buf, nickel_lang::ErrorFormat::Text)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
// Si la propia formateación falla, devolvemos el Debug —
|
||||||
|
// peor mensaje que el normal pero no perdemos info.
|
||||||
|
return format!("{err:?}");
|
||||||
|
}
|
||||||
|
String::from_utf8(buf).unwrap_or_else(|_| format!("{err:?}"))
|
||||||
|
}
|
||||||
@@ -0,0 +1,371 @@
|
|||||||
|
//! Nickel reader + templates.
|
||||||
|
//!
|
||||||
|
//! V2 del brazo: la dispatcher acepta archivos `.ncl`. La evaluación
|
||||||
|
//! produce JSON intermedio que va a los readers estándar, así que un
|
||||||
|
//! `.ncl` puede generar cualquier `CardBody` siempre que su shape sea
|
||||||
|
//! reconocida.
|
||||||
|
//!
|
||||||
|
//! Templates: Nickel `import` + `&` merge nativos. El brazo no
|
||||||
|
//! inventa nada — sólo agrega el parent dir + el env
|
||||||
|
//! `BRAHMAN_CARDS_TEMPLATES_DIR` al import path.
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use brahman_cards::{
|
||||||
|
eval_nickel_file, load_card, CardBody, CardLoadError, NickelEvalError,
|
||||||
|
BRAHMAN_CARDS_TEMPLATES_ENV,
|
||||||
|
};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// Helpers
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
fn unique_dir(name: &str) -> PathBuf {
|
||||||
|
let mut p = std::env::temp_dir();
|
||||||
|
p.push(format!(
|
||||||
|
"brahman-cards-nickel-{}-{}-{}",
|
||||||
|
std::process::id(),
|
||||||
|
nanos(),
|
||||||
|
name
|
||||||
|
));
|
||||||
|
fs::create_dir_all(&p).unwrap();
|
||||||
|
p
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nanos() -> u128 {
|
||||||
|
std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.map(|d| d.as_nanos())
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_file(dir: &std::path::Path, name: &str, content: &str) -> PathBuf {
|
||||||
|
let p = dir.join(name);
|
||||||
|
fs::write(&p, content).unwrap();
|
||||||
|
p
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// 1. Evaluación directa: Nickel → Value
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_nickel_file_returns_value_for_valid_input() {
|
||||||
|
let dir = unique_dir("eval-basic");
|
||||||
|
let p = write_file(
|
||||||
|
&dir,
|
||||||
|
"card.ncl",
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
id = "demo",
|
||||||
|
label = "Demo",
|
||||||
|
entities = [],
|
||||||
|
menu = [],
|
||||||
|
views = {},
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let v = eval_nickel_file(&p).expect("eval ok");
|
||||||
|
assert_eq!(v.get("id"), Some(&json!("demo")));
|
||||||
|
assert_eq!(v.get("label"), Some(&json!("Demo")));
|
||||||
|
assert!(v.get("entities").is_some());
|
||||||
|
fs::remove_dir_all(&dir).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_nickel_file_surfaces_evaluation_error() {
|
||||||
|
let dir = unique_dir("eval-err");
|
||||||
|
let p = write_file(
|
||||||
|
&dir,
|
||||||
|
"broken.ncl",
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
id = "x",
|
||||||
|
label = doesnotexist,
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let err = eval_nickel_file(&p).unwrap_err();
|
||||||
|
match err {
|
||||||
|
NickelEvalError::Eval { path, message } => {
|
||||||
|
assert!(path.contains("broken.ncl"));
|
||||||
|
assert!(!message.is_empty(), "el msg debe traer info de Nickel");
|
||||||
|
}
|
||||||
|
other => panic!("expected Eval error, got {other:?}"),
|
||||||
|
}
|
||||||
|
fs::remove_dir_all(&dir).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// 2. load_card pipeline: .ncl → Card
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_card_dispatches_ncl_to_ui_module_variant() {
|
||||||
|
let dir = unique_dir("dispatch-ui");
|
||||||
|
let p = write_file(
|
||||||
|
&dir,
|
||||||
|
"module.ncl",
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
id = "demo",
|
||||||
|
label = "Demo",
|
||||||
|
entities = [],
|
||||||
|
menu = [{ label = "Stock", view = "stock_list" }],
|
||||||
|
views = {
|
||||||
|
stock_list = {
|
||||||
|
kind = "list",
|
||||||
|
title = "Stock",
|
||||||
|
entity = "Stock",
|
||||||
|
columns = [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let card = load_card(&p).expect("load ok");
|
||||||
|
assert_eq!(card.body.kind_name(), "ui_module");
|
||||||
|
assert_eq!(card.id, "demo");
|
||||||
|
assert_eq!(card.label, "Demo");
|
||||||
|
fs::remove_dir_all(&dir).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_card_dispatches_ncl_to_ente_variant() {
|
||||||
|
let dir = unique_dir("dispatch-ente");
|
||||||
|
let p = write_file(
|
||||||
|
&dir,
|
||||||
|
"ente.ncl",
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
schema_version = 1,
|
||||||
|
id = "01ARZ3NDEKTSV4RRFFQ69G5FAV",
|
||||||
|
label = "test-ente",
|
||||||
|
payload = "Virtual",
|
||||||
|
supervision = "OneShot",
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let card = load_card(&p).expect("load ok");
|
||||||
|
assert_eq!(card.body.kind_name(), "ente");
|
||||||
|
assert_eq!(card.id, "01ARZ3NDEKTSV4RRFFQ69G5FAV");
|
||||||
|
fs::remove_dir_all(&dir).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// 3. Templates: import + merge native de Nickel
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
/// El caso de uso que el usuario describió: "un Card simple usa un
|
||||||
|
/// Card ya hecho cambiando sólo nombre y id". Template define la
|
||||||
|
/// shape full; el archivo concreto importa + override.
|
||||||
|
#[test]
|
||||||
|
fn template_merge_overrides_id_and_label_only() {
|
||||||
|
let dir = unique_dir("template-merge");
|
||||||
|
|
||||||
|
// Template con la shape full de un UiModule. Los campos
|
||||||
|
// sobrescribibles se marcan `| default` — Nickel sólo permite
|
||||||
|
// override en merge cuando hay diferencia de prioridad. Sin
|
||||||
|
// `| default` los strings no-iguales fallan con "non mergeable".
|
||||||
|
write_file(
|
||||||
|
&dir,
|
||||||
|
"ui_module_basic.ncl",
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
id | String | default = "TEMPLATE_ID",
|
||||||
|
label | String | default = "TEMPLATE_LABEL",
|
||||||
|
description = "stock + form básico",
|
||||||
|
entities = [
|
||||||
|
{ name = "Item", label = "Item", fields = [] },
|
||||||
|
],
|
||||||
|
menu = [
|
||||||
|
{ label = "Items", view = "items_list" },
|
||||||
|
{ label = "+ Item", view = "items_form" },
|
||||||
|
],
|
||||||
|
views = {
|
||||||
|
items_list = {
|
||||||
|
kind = "list",
|
||||||
|
title = "Items",
|
||||||
|
entity = "Item",
|
||||||
|
columns = [],
|
||||||
|
},
|
||||||
|
items_form = {
|
||||||
|
kind = "form",
|
||||||
|
title = "Nuevo item",
|
||||||
|
entity = "Item",
|
||||||
|
fields = [],
|
||||||
|
on_submit = {
|
||||||
|
kind = "seed_entity",
|
||||||
|
entity = "Item",
|
||||||
|
next_view = "items_list",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Card concreto: import + merge override.
|
||||||
|
let p = write_file(
|
||||||
|
&dir,
|
||||||
|
"my_module.ncl",
|
||||||
|
r#"
|
||||||
|
let base = import "ui_module_basic.ncl" in
|
||||||
|
base & {
|
||||||
|
id = "my_module",
|
||||||
|
label = "Mi Módulo",
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let card = load_card(&p).expect("template merge ok");
|
||||||
|
assert_eq!(card.id, "my_module", "el override del id se aplicó");
|
||||||
|
assert_eq!(card.label, "Mi Módulo", "el override del label se aplicó");
|
||||||
|
assert_eq!(card.body.kind_name(), "ui_module");
|
||||||
|
match card.body {
|
||||||
|
CardBody::UiModule(m) => {
|
||||||
|
// El resto viene del template intacto.
|
||||||
|
assert_eq!(m.menu.len(), 2);
|
||||||
|
assert_eq!(m.entities.len(), 1);
|
||||||
|
assert_eq!(m.entities[0].name, "Item");
|
||||||
|
}
|
||||||
|
other => panic!("variant inesperado: {:?}", other.kind_name()),
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::remove_dir_all(&dir).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// El env `BRAHMAN_CARDS_TEMPLATES_DIR` permite tener un registry
|
||||||
|
/// global: el usuario importa por nombre desnudo desde cualquier
|
||||||
|
/// ubicación.
|
||||||
|
///
|
||||||
|
/// Este test setea/unset el env de forma local (no thread-safe en
|
||||||
|
/// tests paralelos contra el mismo env, pero usamos una key dedicada
|
||||||
|
/// y borramos después). Si se vuelve flaky, agregar mutex.
|
||||||
|
#[test]
|
||||||
|
fn template_resolves_via_env_registry() {
|
||||||
|
let registry = unique_dir("template-registry");
|
||||||
|
let inputs = unique_dir("template-input");
|
||||||
|
|
||||||
|
write_file(
|
||||||
|
®istry,
|
||||||
|
"ui_module_minimal.ncl",
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
id | String | default = "X",
|
||||||
|
label | String | default = "X",
|
||||||
|
entities = [],
|
||||||
|
menu = [],
|
||||||
|
views = {},
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let p = write_file(
|
||||||
|
&inputs,
|
||||||
|
"from_registry.ncl",
|
||||||
|
r#"
|
||||||
|
let base = import "ui_module_minimal.ncl" in
|
||||||
|
base & { id = "registry_user", label = "Usado del Registry" }
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set env, evaluar, restaurar.
|
||||||
|
let prev = std::env::var(BRAHMAN_CARDS_TEMPLATES_ENV).ok();
|
||||||
|
// SAFETY: nickel-lang tests modifican un env ad-hoc que no es
|
||||||
|
// referenciado por nada externo y se restaura al salir. Ningún
|
||||||
|
// otro test del crate lee este env.
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var(BRAHMAN_CARDS_TEMPLATES_ENV, ®istry);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = load_card(&p);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if let Some(v) = prev {
|
||||||
|
std::env::set_var(BRAHMAN_CARDS_TEMPLATES_ENV, v);
|
||||||
|
} else {
|
||||||
|
std::env::remove_var(BRAHMAN_CARDS_TEMPLATES_ENV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let card = result.expect("template via registry ok");
|
||||||
|
assert_eq!(card.id, "registry_user");
|
||||||
|
assert_eq!(card.body.kind_name(), "ui_module");
|
||||||
|
|
||||||
|
fs::remove_dir_all(®istry).ok();
|
||||||
|
fs::remove_dir_all(&inputs).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// 4. Errores propagan limpios al CardLoadError
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_card_wraps_nickel_error_in_card_load_error() {
|
||||||
|
let dir = unique_dir("wrap-err");
|
||||||
|
let p = write_file(&dir, "bad.ncl", "let x = unknown in x");
|
||||||
|
let err = load_card(&p).unwrap_err();
|
||||||
|
match err {
|
||||||
|
CardLoadError::Nickel(NickelEvalError::Eval { .. }) => {} // expected
|
||||||
|
other => panic!("expected Nickel(Eval), got {other:?}"),
|
||||||
|
}
|
||||||
|
fs::remove_dir_all(&dir).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// El value-add concreto de Nickel sobre JSON: un contract
|
||||||
|
/// violation se captura en evaluación, ANTES de que el reader
|
||||||
|
/// JSON tenga oportunidad de aceptar un shape mal-tipado. Acá un
|
||||||
|
/// `id | String` con un value que no es String falla en eval-time
|
||||||
|
/// con un mensaje legible. JSON puro lo aceptaría y rompería más
|
||||||
|
/// tarde aguas abajo.
|
||||||
|
#[test]
|
||||||
|
fn nickel_contract_violation_caught_at_eval_time() {
|
||||||
|
let dir = unique_dir("contract-violation");
|
||||||
|
let p = write_file(
|
||||||
|
&dir,
|
||||||
|
"bad_id.ncl",
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
id | String = 42,
|
||||||
|
label = "X",
|
||||||
|
entities = [],
|
||||||
|
menu = [],
|
||||||
|
views = {},
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let err = load_card(&p).unwrap_err();
|
||||||
|
match err {
|
||||||
|
CardLoadError::Nickel(NickelEvalError::Eval { message, .. }) => {
|
||||||
|
// Mensaje de contract violation legible.
|
||||||
|
assert!(
|
||||||
|
message.contains("contract") || message.contains("String"),
|
||||||
|
"msg debe mencionar contract o String: {message}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
other => panic!("expected Nickel(Eval), got {other:?}"),
|
||||||
|
}
|
||||||
|
fs::remove_dir_all(&dir).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sanity: un Nickel que evalúa a un shape NO-reconocible (no
|
||||||
|
/// matchea ningún reader) cae en `NoMatchingReader` — la cadena
|
||||||
|
/// Nickel + dispatcher se mantiene coherente.
|
||||||
|
#[test]
|
||||||
|
fn ncl_evaluating_to_unknown_shape_returns_no_matching_reader() {
|
||||||
|
let dir = unique_dir("unknown-shape");
|
||||||
|
let p = write_file(
|
||||||
|
&dir,
|
||||||
|
"weird.ncl",
|
||||||
|
r#"{ random = "shape", without = "fingerprint" }"#,
|
||||||
|
);
|
||||||
|
let err = load_card(&p).unwrap_err();
|
||||||
|
assert!(
|
||||||
|
matches!(err, CardLoadError::NoMatchingReader),
|
||||||
|
"expected NoMatchingReader, got {err:?}"
|
||||||
|
);
|
||||||
|
fs::remove_dir_all(&dir).ok();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user