WoodyLab
WoodyLabBuild with UIMS

Documentazione · src/engine/resolver

I resolver

Tredici file, un contratto solo. Un blocco entra, esce un descrittore — o niente, che è una risposta legittima.

Il contratto: un descrittore, sempre lo stesso

Ogni resolver riceve `(block, context)` e restituisce la stessa forma: `Component` (chi disegna), `ui` (le props strutturali — classi, tag, attributi), `slots` (i figli già proiettati, per apertura), `items` (le righe, quando il blocco ne ha), `data` (tutto il dominio).

La separazione fra `data` e le chiavi strutturali non è ordine per l’ordine. È ciò che permette a un componente di essere scritto senza sapere quale blocco lo userà: legge da `data` quello che gli serve per nome, e le chiavi strutturali le consuma il primitivo comune. Mescolare le due cose — mettere il testo dentro `ui` — funzionerebbe per un componente e romperebbe la sostituibilità di tutti.

  • resolver/contract.ts — la forma del descrittore, e il tipo di una funzione resolver
  • resolver/index.ts — il registro: quale resolver per quale `blockType`

Il resolver di default fa quasi tutto

La maggior parte dei blocchi non ha un resolver proprio e passa da `resolveViewMode`: trova il viewMode per nome nel tema attivo (con fallback su `uims`), lo fonde con l’override del tema, ne ricava componente, classi, tag e slot, proietta i figli nelle aperture giuste e mette tutto il resto in `data`.

Un resolver dedicato serve solo quando il blocco ha bisogno di qualcosa che non è nel blocco stesso: un documento da dereferenziare, dei record da leggere, un form da iniettare. Sono i casi delle sezioni successive — sette in tutto su una trentina di tipi di blocco.

  • resolver/resolveViewMode.ts — il default: viewMode → componente, classi, slot; il resto in `data`

Una sezione non è un componente

Una sezione è una composizione: sezione contiene contenitore contiene contenuto. Non ha un componente proprio, e infatti il suo descrittore non porta `Component` — è così che il renderer distingue le due cose senza un flag.

La conseguenza è che una sezione non si può disegnare «da sola»: è una struttura di tre livelli, ognuno con il suo viewMode e le sue classi. Ed è il motivo per cui i seeder del sito costruiscono le pagine con un helper `sec({ section, container, content })` invece che con un blocco piatto.

  • resolver/sectionResolver.ts — la composizione a tre livelli; nessun `Component`
  • resolver/sectionRefResolver.ts — dereferenzia la sezione e restituisce ciò che il resolver di sopra ha prodotto

I riferimenti sono delega pura

Un blocco `reference` non ha una forma propria: punta a un documento, e ciò che va disegnato è quel documento con la forma che il suo resolver gli dà. Il resolver quindi non fa altro che risolvere il riferimento e restituire il descrittore altrui.

La lettura è deduplicata per richiesta e messa in cache con il tag del documento: dieci blocchi che puntano allo stesso record leggono una volta sola, e la modifica di quel record invalida esattamente quelle pagine. È il pezzo di DAL che rende sostenibile una pagina composta di riferimenti.

  • resolver/referenceResolver.ts — risolve il documento riferito e restituisce il suo descrittore

Le viste: dei record dentro gli slot di un guscio

Una vista è «prendi N record e mappali dentro questa forma». I record possono venire da una collection interna o da una sorgente esterna via HTTP; la forma è un guscio (una griglia, una navigazione, una card) con delle aperture, e la mappatura dice quale campo del record finisce in quale apertura.

Tre resolver condividono la stessa mappatura e differiscono solo per la provenienza dei record. `viewResolver` legge da una query. `mappedReferenceResolver` li raggiunge attraverso una relazione. `pathBindingResolver` percorre una struttura ricorsiva — un menu con i figli — mappando ogni nodo con la stessa regola e ricorrendo negli slot.

La navigazione ha un caso a parte perché non ha bisogno di mappatura: le voci del menu arrivano già nella forma giusta e finiscono in `data.navigation`, che è quello che il componente legge.

  • resolver/viewResolver.ts — record da collection interna o sorgente esterna, mappati negli slot
  • resolver/mappedReferenceResolver.ts — stessa mappatura, record raggiunti tramite relazione
  • resolver/pathBindingResolver.ts — un nodo di menu mappato, con i figli che ricorrono negli slot
  • resolver/navigationResolver.ts — le voci del menu in `data.navigation`

I form

Il blocco form è un contenitore con dentro il form riferito: i dati operativi (dove si invia, cosa si fa dopo) restano in `data`, gli input finiscono negli slot come figli. Il componente `Form` monta il contesto e i controlli si registrano da soli.

La forma dei singoli input viene dai viewMode come per qualunque altro blocco: un campo di testo si può ridisegnare senza toccare la logica di invio, che sta altrove.

  • resolver/formResolver.ts — il form riferito iniettato nel contenitore; dati operativi in `data`

Le reazioni risolte prima del client

Sull’istanza di un blocco si dichiara «quando succede X, fai Y»: un trigger e una conseguenza. La conseguenza spesso nomina una ricetta di animazione, che è un dato — vive nello store, non nel codice.

`resolveReactions` traduce quelle dichiarazioni nella forma che il nodo reattivo applicherà sul client, andando a prendere le ricette dal registro. Una reazione la cui ricetta non esiste viene lasciata cadere in silenzio: un’animazione mancante non è una ragione per non disegnare la pagina.

  • resolver/resolveReactions.ts — dalle dichiarazioni dell’istanza alla forma che applica `UIMSReactive`
Login