WoodyLab
WoodyLabBuild with UIMS

Documentazione · src/engine

Il motore

Sette file alla radice e quattro sottocartelle. Qui il dato diventa qualcosa che si può disegnare, e succede sul server — prima che React esista.

Un blocco è un dato con quattro chiavi lette per nome

Di tutto quello che un blocco contiene, il motore ne guarda quattro cose. `blockType` dice quale resolver lo tratta. `viewMode` nomina la forma. `slot` dice in quale apertura del genitore va proiettato. `content` tiene i figli. Tutto il resto — il testo, l’immagine, l’href, i campi che quel tipo di blocco ha — appartiene al blocco e il motore non lo interpreta: lo passa.

È una scelta con una conseguenza precisa: aggiungere un campo a un blocco non richiede di toccare il motore. Il campo finisce in `data` e arriva al componente. Il motore resta ignorante del dominio, che è la ragione per cui non cresce quando cresce il progetto.

  • engine/block.ts — il tipo `UimsBlock`: le quattro chiavi note più l’apertura al resto

Il contesto: una mappa da tipo di blocco a resolver

`createUIMSContext` costruisce l’oggetto che il progetto tiene in `uimsContext.ts` e usa in ogni pagina: `UIMS.resolve(block)`. Dentro non c’è nient’altro che una mappa da `blockType` alla funzione che lo tratta, più il default per tutti i tipi che non ne hanno uno dedicato.

Un resolver può restituire `null`, e questo è il dettaglio che evita una classe intera di crash: un `sectionRef` che punta a una sezione cancellata risolve a niente. Non è un errore, è la risposta giusta — la sezione non c’è. Il renderer salta il descrittore vuoto e la pagina esce lo stesso.

Il blocco in ingresso resta `any`, e non per pigrizia: il tipo di un blocco dipende dalla configurazione del progetto, che il pacchetto non conosce. La tipizzazione forte sta dall’altra parte, sul descrittore che esce.

  • engine/createUIMSContext.ts — costruisce il contesto: registro dei resolver, default, e `resolve`
  • engine/index.ts — la porta pubblica dell’area

Gli store, tipizzati una volta sola

`db.viewmodes.json` e `db.styles.json` sono le due sorgenti di forma, e per parecchio tempo sono entrati nel motore come `any[]`. Il risultato era che ogni punto che li usava scriveva `viewModesDb as any[]` al momento della chiamata — un cast che sembra una precauzione e in realtà è una rinuncia ripetuta: nessuno dei consumatori sapeva davvero cosa ci fosse dentro.

`store.ts` dichiara `ViewModeDef` e `StyleDef` una volta, e i consumatori smettono di castare. Il tipo descrive lo STORE, non la forma a runtime: quello che esce dal registry è già fuso con l’override del tema e normalizzato per il renderer, ed è un’altra cosa — descritta in `engine/types.ts`.

  • engine/store.ts — `ViewModeDef` e `StyleDef`: cosa contengono i due store

I tipi degli slot stanno dove servono

I quattro tipi che descrivono gli slot — la definizione, l’istanza di un figlio, lo slot risolto e la mappa di tutti — vivevano in `react/type.ts`, insieme alle props dei componenti. Da lì li importavano cinque file del motore: i tre mapper e le due utility di proiezione. La dipendenza andava nel verso sbagliato: il motore importava dal render.

Ora stanno in `engine/types.ts`, e `react/type.ts` li ri-esporta. Chi scrive un componente continua a importarli da `@woodylab/uims/react`, che è la porta giusta per lui; il motore non attraversa più il confine.

  • engine/types.ts — `SlotDefinition`, `ChildInstance`, `ResolvedSlot`, `ResolvedSlots`

Compatibilità: quali viewMode possono disegnare un blocco

Il motore è aperto per scelta: un viewMode è riferito per NOME, e niente vieta di accoppiare qualunque blocco a qualunque forma. Il costo di quell’apertura è il silenzio — dai al blocco `icon` un viewMode che nomina il componente `Action` e non succede niente di visibile, semplicemente non appare quello che ti aspettavi.

`compatibility.ts` non chiude l’apertura, la RENDE VISIBILE: sa quale componente ci si aspetta per un tipo di blocco e può dirlo. È materiale per l’interfaccia — l’admin propone prima i viewMode compatibili — non un divieto a runtime.

  • engine/compatibility.ts — la relazione blocco → viewMode plausibili
  • engine/resolver/compatibilityRuntime.ts — quale componente ci si aspetta per un tipo di blocco, calcolato al caricamento

Il vocabolario degli eventi: due insiemi, nessuno derivato dall’altro

Cosa può dire l’interfaccia è l’unione di due cose diverse. Gli HANDLER sono ciò che esiste e RISPONDE: quelli del pacchetto più quelli del progetto. Il catalogo `db.events.json` è ciò che è DICHIARATO: i nomi che l’admin propone in una tendina.

I due insiemi non coincidono e non devono. Un handler può esistere senza essere dichiarato — nessuno lo sceglie da interfaccia ma il codice lo può chiamare. Un nome può essere dichiarato senza handler — è il caso degli eventi di stato, che non hanno un handler perché li tratta il reducer. Derivare l’uno dall’altro avrebbe cancellato entrambi i casi legittimi.

  • engine/eventVocabulary.ts — l’unione dei due insiemi, per chi deve mostrare un elenco

Le quattro sottocartelle

Il resto del motore è diviso per passaggio: chi decide la forma di un blocco (`resolver`), chi porta i dati dentro gli slot (`mapper`), chi calcola le classi (`styling`), chi legge dal database con la cache giusta (`dal`). Più tre utility di proiezione che stanno in `utils` perché le usano tutti.

La dipendenza fra loro è a senso unico: `styling` non conosce nessuno, `mapper` usa `styling`, `resolver` usa entrambi. Era circolare finché i tre file di stile stavano dentro `resolver/`, ed è il motivo per cui sono usciti.

  • engine/resolver/ — tredici file: dal blocco al descrittore
  • engine/mapper/ — quattro file: dai dati agli slot
  • engine/styling/ — tre file: dal viewMode alle classi
  • engine/dal/ — tredici file: la lettura cache-aware
  • engine/utils/ — tre file: estrazione delle props di UI e proiezione degli slot in React
Login