@esfaenza/dpe-builder 20.3.12 → 20.3.13

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/index.d.ts CHANGED
@@ -217,9 +217,18 @@ interface AggregateNode extends DpeNode {
217
217
  type TransformKind = 'Expression' | 'Slice' | 'ComputeRelative';
218
218
  interface ExpressionField extends DpeExtensible {
219
219
  alias: string;
220
- /** **SQL nativo del dialetto della definizione** (ADR 0006): passa verbatim. */
220
+ /**
221
+ * Una **formula** nel linguaggio del compilatore registrato dall'ospite (ADR 0031): non e'
222
+ * SQL, e il frontend non ne conosce la grammatica. Forma `Value` sotto `Expression`, forma
223
+ * `WindowFunction` sotto `ComputeRelative`.
224
+ */
221
225
  expression: string;
222
- /** **Autorevole e non verificato** (ADR 0006). */
226
+ /**
227
+ * **Dichiarato dall'utente e autorevole** (ADR 0033): lo schema resta una funzione pura della
228
+ * definizione, quindi il tipo di una colonna calcolata e' questo e non quello inferito dal
229
+ * compilatore. Il compilatore lo **verifica** — `DPE_EXPR_TYPE_MISMATCH` /
230
+ * `DPE_EXPR_TYPE_WIDENED` / `DPE_EXPR_TYPE_UNVERIFIED` — ma non lo determina.
231
+ */
223
232
  declaredType: ColumnType;
224
233
  }
225
234
  interface TransformNode extends DpeNode {
@@ -316,6 +325,16 @@ interface CustomNode extends DpeNode {
316
325
  type WritebackTargetKind = 'Database' | 'Json' | 'Csv';
317
326
  type WritebackOperation = 'Insert' | 'Update' | 'Upsert' | 'Delete';
318
327
  type WritebackFieldRole = 'Value' | 'PrimaryKey' | 'QualifierKey';
328
+ /**
329
+ * Granularita' del fallimento che l'host deve rispettare applicando un writeback (ADR 0040).
330
+ *
331
+ * `PerRecord`: l'host **puo'** applicare le righe indipendentemente e riportare i fallimenti per
332
+ * riga. `Atomic`: l'host **deve** applicare l'intero writeback in una transazione sola.
333
+ *
334
+ * Dichiarata e **non eseguita**: la libreria non apre transazioni e questo valore non cambia di
335
+ * una virgola l'SQL generato.
336
+ */
337
+ type WritebackFailureHandling = 'Atomic' | 'PerRecord';
319
338
  interface WritebackFieldMapping extends DpeExtensible {
320
339
  /** Condiz.: alias a monte; assente quando `runtimeParameterName` e' presente. */
321
340
  sourceFieldName?: string;
@@ -361,12 +380,34 @@ interface WritebackNode extends DpeNode {
361
380
  operation?: WritebackOperation;
362
381
  /** Obbligatorio (>=1) in un nodo valido. */
363
382
  fields?: WritebackFieldMapping[];
364
- /** Espressione SQL nativa applicata al risultato (ADR 0006). */
383
+ /**
384
+ * Predicato applicato al risultato: e' il **terzo sito di authoring di formule** (ADR 0031 §1),
385
+ * quello che si dimentica, e passa dal compilatore nella forma `Predicate`. Non e' SQL.
386
+ */
365
387
  filterCondition?: string;
366
388
  /** Condiz.: richiesto per `operation === 'Upsert'`. */
367
389
  externalIdFieldName?: string;
368
390
  /** Default `false`. */
369
391
  onlyChangedRows?: boolean;
392
+ /**
393
+ * `targetFieldName` della colonna con cui l'host raggruppa le righe per la rilavorazione
394
+ * (ADR 0040). Solo `target === 'Database'`. Dichiarato e non eseguito: la libreria non
395
+ * raggruppa niente, e senza questo campo l'unico lotto di lavoro possibile e' il writeback
396
+ * intero.
397
+ */
398
+ processingGroupFieldName?: string;
399
+ /**
400
+ * Solo `target === 'Database'`, e **assente** vuol dire «non dichiarato», che non e' la stessa
401
+ * cosa di `PerRecord`: il valore efficace lo calcola il backend e arriva su
402
+ * `DpeWritebackStep.failureHandling`.
403
+ *
404
+ * L'opzionalita' non e' comodita': e' cio' che permette a un salva-dopo-carica di rispedire il
405
+ * documento **identico** (**I7**). Se l'editor scrivesse un default qui, una definizione che non
406
+ * dichiara niente tornerebbe al backend dichiarando `PerRecord`, e su un membro di gruppo
407
+ * atomico quella riga in piu' diventerebbe `DPE_MODEL_CONDITIONAL_FORBIDDEN` su un campo che
408
+ * nessuno ha toccato.
409
+ */
410
+ failureHandling?: WritebackFailureHandling;
370
411
  /** Solo `target === 'Json'`. */
371
412
  jsonOptions?: JsonArtifactOptions;
372
413
  /** Solo `target === 'Csv'`. */
@@ -415,7 +456,14 @@ type DpeAnyNode = DpeNodeCollectionMap[DpeNodeCollectionName];
415
456
  /**
416
457
  * L'elenco dei nomi di collezione in forma di valore, nell'ordine in cui i nodi si leggono
417
458
  * (sorgenti -> trasformazioni -> sink). `keyof` non produce un array a runtime: questo
418
- * elenco e' l'unico posto in cui vive l'ordine.
459
+ * elenco e' l'unico posto in cui vive l'ordine. Lo leggono il cammino del documento
460
+ * (`dpe-graph.ts`) e la palette, attraverso `DPE_NODE_CATEGORIES` che ne deriva.
461
+ *
462
+ * **Totale e senza ripetizioni, e a dirlo e' il compilatore.** Un array non si verifica contro
463
+ * un'unione: una collezione aggiunta a `DpeNodeCollectionMap` e dimenticata qui compilerebbe, e
464
+ * sparirebbe in silenzio dal cammino del documento (archi che non compaiono, rinomine
465
+ * incomplete) e dalla palette. Il controllo `COLLECTION_ORDER_IS_TOTAL` trasforma l'omissione, e
466
+ * la ripetizione, in un errore di build che nomina il membro.
419
467
  */
420
468
  declare const DPE_NODE_COLLECTIONS: readonly DpeNodeCollectionName[];
421
469
 
@@ -474,6 +522,18 @@ interface Diagnostic {
474
522
  * duplicazione del dominio: e' la sola distinzione che cambia **come si rende** un rilievo.
475
523
  */
476
524
  declare const DPE_NODE_NOT_COMPILABLE = "DPE_NODE_NOT_COMPILABLE";
525
+ /**
526
+ * Il codice che il contratto (`contracts.md` §5 e §7) prescrive di mostrare **in testa** quando il
527
+ * catalogo delle formule non e' stato prodotto: nomina la sorgente il cui schema non si risolve,
528
+ * mentre le diagnostiche strutturali che lo accompagnano ne dicono la causa.
529
+ *
530
+ * Seconda e ultima costante di codice dichiarata dalla libreria, per lo stesso criterio della
531
+ * prima: non e' un elenco di dominio duplicato, e' l'unica cosa che cambia **come si rende** un
532
+ * sacco di rilievi. Senza di essa la riga che l'architetto ha aggiunto apposta — «una riga da
533
+ * mostrare in testa» — finirebbe in mezzo alle altre, che e' il rumore indistinguibile che il
534
+ * codice esiste per evitare.
535
+ */
536
+ declare const DPE_CATALOG_UNAVAILABLE = "DPE_CATALOG_UNAVAILABLE";
477
537
  /** Rappresentazione testuale del percorso, nella forma usata dai messaggi del backend. */
478
538
  declare function diagnosticPathToString(path: DiagnosticPath | undefined): string;
479
539
 
@@ -498,6 +558,172 @@ declare function diagnosticPathToString(path: DiagnosticPath | undefined): strin
498
558
  interface DpeEnvironment {
499
559
  /** Il dialetto del database di destinazione. Dichiarato, mai scelto dall'utente dell'editor. */
500
560
  readonly dialect: SqlDialectKind;
561
+ /**
562
+ * Nome del linguaggio in cui si scrivono le espressioni, dal compilatore di formule registrato
563
+ * dall'ospite (ADR 0031/0036).
564
+ *
565
+ * Serve **all'etichetta del campo**, e per questo sta qui e non nel catalogo: il catalogo puo'
566
+ * legittimamente non arrivare — il compilatore non descrive il proprio linguaggio
567
+ * (`ProvidesCatalog == false`), oppure il dialetto della definizione non e' fra quelli che
568
+ * copre e allora il catalogo e' nullo — mentre il nome del linguaggio si sa sempre. Un editor
569
+ * che leggesse il nome dal catalogo resterebbe muto proprio nei casi in cui l'utente ha piu'
570
+ * bisogno di sapere in che lingua sta scrivendo.
571
+ *
572
+ * Assente = l'editor non nomina nessun linguaggio. Non nomina il **dialetto** al suo posto: il
573
+ * dialetto non c'entra piu' con cio' che si scrive in quel campo (ADR 0031).
574
+ */
575
+ readonly expressionLanguage?: string;
576
+ /**
577
+ * Il compilatore descrive il proprio linguaggio. Falso o assente: **non chiamare**
578
+ * `getFormulaCatalog`.
579
+ *
580
+ * Si interroga **prima** di chiamare, per la stessa ragione per cui la disponibilita' di un
581
+ * comando si sa prima del clic (`contracts.md` §7): una chiamata che si sa inutile costa al
582
+ * backend una passata completa di grafo e di metadati per restituire un catalogo vuoto.
583
+ */
584
+ readonly providesFormulaCatalog?: boolean;
585
+ /**
586
+ * Le **forme** che il compilatore registrato sa produrre (`Capabilities.SupportedForms`, ADR
587
+ * 0031). Incrociata con `DpeNodeSchemaInfo.requiredForm` — che e' per **nodo** e arriva con la
588
+ * validazione — permette di **disabilitare** un campo formula che non potra' mai essere
589
+ * compilato.
590
+ *
591
+ * Le due meta' stanno in due posti perche' hanno due sorgenti e due vite: la forma richiesta
592
+ * viene dalla **definizione**, le forme supportate dal **compilatore registrato**, cioe'
593
+ * dall'installazione, come `expressionLanguage` e `providesFormulaCatalog` qui accanto.
594
+ * L'editor le incrocia e non deduce nessuna delle due.
595
+ *
596
+ * **Assente (o `null`) significa: non si disabilita niente.** Non e' un ripiego prudente, e' la
597
+ * politica: non sapere quali forme il compilatore copra non autorizza a indovinare, e un campo
598
+ * spento per ignoranza e' peggio di un campo acceso che il backend rifiutera' dicendo perche'.
599
+ * Un elenco **vuoto** e' un'altra cosa — e' una dichiarazione, e dice «nessuna forma».
600
+ *
601
+ * Opzionale **e** nullabile per la regola dei tipi di rispecchiamento: descrivono cio' che
602
+ * arriva **sul filo**, e l'ospite di riferimento ignora i nulli come politica globale, quindi la
603
+ * proprieta' puo' non comparire affatto.
604
+ */
605
+ readonly supportedForms?: readonly DpeExpressionForm[] | null;
606
+ }
607
+ /**
608
+ * La **forma** che i siti di espressione di un nodo pretendono (ADR 0031 §1).
609
+ *
610
+ * Attraversa il confine su `DpeNodeSchemaInfo.requiredForm` per una ragione sola: dedurla dal tipo
611
+ * di nodo — «una trasformazione `Expression` vuole un valore, il filtro di un writeback vuole un
612
+ * predicato» — sarebbe una **regola di dominio in TypeScript**, che e' vietata. La sa il backend, e
613
+ * la dice.
614
+ *
615
+ * Il tipo sta in questa sezione e non accanto agli schemi perche' e' la **stessa** enumerazione che
616
+ * `DpeEnvironment.supportedForms` dichiara: sono i due operandi dell'incrocio, e un'enumerazione
617
+ * dichiarata due volte diverge.
618
+ */
619
+ type DpeExpressionForm = 'Value' | 'Predicate' | 'WindowFunction';
620
+ /**
621
+ * L'**involucro** di `getFormulaCatalog`, rispecchiamento di `DpeFormulaCatalogResult`
622
+ * (`contracts.md` §7, normativo). La rotta consegna questo, non il catalogo nudo.
623
+ *
624
+ * Il motivo e' misurato, non di principio: il service distingue **tre** esiti e il filo ne
625
+ * consegnava **due** — o un catalogo o un errore di trasporto — quindi *dialetto non coperto* e
626
+ * *backend rotto* arrivavano all'editor identici, e il degrado era silenzioso.
627
+ *
628
+ * **Il discriminante e' `diagnostics`, non `catalog`:** diagnostiche non vuote significa
629
+ * fallimento, e si mostrano; altrimenti un catalogo c'e', e la tavolozza si mostra se ha
630
+ * contenuto. In particolare un compilatore che non descrive il proprio linguaggio consegna il
631
+ * catalogo **presente e vuoto**, con `languageName` valorizzato e zero diagnostiche: chi ramasse
632
+ * su `catalog == null` non entrerebbe **mai** in quel caso.
633
+ *
634
+ * La derivazione dei tre esiti sta in `dpeFormulaCatalogOutcome`, una funzione pura, e non in un
635
+ * `if` dentro un componente.
636
+ */
637
+ interface DpeFormulaCatalogResult {
638
+ /**
639
+ * Il catalogo. **Assente o `null` significa una cosa sola: non e' stato prodotto** — non
640
+ * «prodotto vuoto», che e' un esito diverso e si riconosce dagli elenchi vuoti.
641
+ *
642
+ * Opzionale **e** nullabile insieme, e non e' pignoleria: un tipo di rispecchiamento descrive
643
+ * cio' che arriva **sul filo**, non cio' che il record C# dichiara, e ospiti diversi
644
+ * serializzano diversamente. L'ospite di riferimento ignora i nulli come politica globale,
645
+ * quindi la proprieta' non compare affatto e arriva `undefined` mentre un tipo con il solo
646
+ * `| null` prometterebbe altro. `check:modelli` confronta i **nomi** dei campi e questa classe
647
+ * di divergenza non la vede.
648
+ */
649
+ readonly catalog?: DpeFormulaCatalog | null;
650
+ /**
651
+ * Le diagnostiche del service. Mai nulla; **vuota** quando il compilatore semplicemente non
652
+ * descrive il proprio linguaggio, che non e' un errore.
653
+ *
654
+ * `DPE_CATALOG_UNAVAILABLE` e' la riga da mostrare **in testa**: nomina la sorgente il cui
655
+ * schema non si risolve, e le strutturali che la seguono ne dicono la causa. Non si filtrano
656
+ * per pertinenza — l'errore che spiega lo schema puo' stare a piu' salti di distanza — quindi
657
+ * diventano dettaglio espandibile invece di rumore indistinguibile.
658
+ */
659
+ readonly diagnostics: readonly Diagnostic[];
660
+ readonly hasErrors: boolean;
661
+ }
662
+ /**
663
+ * Rispecchiamento sul filo di `Jace.DPE.Expressions.DpeFormulaCatalog`: cosa il linguaggio di
664
+ * formule dell'ospite mette a disposizione **nel punto** in cui si sta scrivendo.
665
+ *
666
+ * **Non e' una regola di dominio e non ne diventa una** (`contracts.md` §7). L'editor lo usa per
667
+ * *mostrare* cosa esiste; non lo usa per validare cio' che l'utente scrive. La grammatica e' del
668
+ * compilatore, il frontend non la conosce, e nessuna validazione di formula viene scritta in
669
+ * TypeScript — per nessun motivo, nemmeno «solo per il caso banale»: una regola duplicata diverge,
670
+ * e quando diverge l'editor mente all'utente.
671
+ *
672
+ * Un catalogo **vuoto e' legittimo** (ADR 0036 §5) e non e' un errore: significa che il
673
+ * compilatore non descrive il proprio linguaggio, e l'editor mostra un campo di testo semplice.
674
+ */
675
+ interface DpeFormulaCatalog {
676
+ /**
677
+ * Nome del linguaggio secondo il compilatore. **Non** e' la fonte dell'etichetta del campo:
678
+ * quella e' `DpeEnvironment.expressionLanguage`, che arriva anche quando il catalogo non arriva.
679
+ */
680
+ readonly languageName: string;
681
+ readonly functions: readonly DpeFormulaFunction[];
682
+ readonly operators: readonly DpeFormulaOperator[];
683
+ readonly symbols: readonly DpeFormulaSymbol[];
684
+ }
685
+ interface DpeFormulaFunction {
686
+ /** Gruppo con cui l'elenco raggruppa la voce. */
687
+ readonly group: string;
688
+ readonly name: string;
689
+ readonly description?: string;
690
+ /**
691
+ * Assente quando il tipo di ritorno **dipende dagli argomenti** e un elenco statico non puo'
692
+ * dichiararlo (ADR 0036 §4). Assente significa «non si sa qui», non `String`.
693
+ */
694
+ readonly returnType?: ColumnType;
695
+ readonly parameters: readonly DpeFormulaFunctionParameter[];
696
+ }
697
+ interface DpeFormulaFunctionParameter {
698
+ readonly name: string;
699
+ readonly description?: string;
700
+ readonly type?: ColumnType;
701
+ readonly isOptional?: boolean;
702
+ /**
703
+ * Il parametro appartiene a un gruppo che **si ripete** (funzione variadica). Un solo campo al
704
+ * posto della coppia gruppo/ordine del sistema di origine: il matching delle firme e' lavoro del
705
+ * compilatore, a un elenco per l'utente serve sapere che il gruppo si ripete.
706
+ */
707
+ readonly isRepeating?: boolean;
708
+ }
709
+ interface DpeFormulaOperator {
710
+ readonly group: string;
711
+ readonly symbol: string;
712
+ readonly description?: string;
713
+ }
714
+ /**
715
+ * Provenienza di un simbolo. Le tre sono strutturalmente diverse e l'elenco le raggruppa: una
716
+ * colonna a monte, un parametro di runtime della definizione e una costante del linguaggio non si
717
+ * correggono nello stesso modo quando il nome e' sbagliato.
718
+ */
719
+ type DpeFormulaSymbolKind = 'Column' | 'Parameter' | 'Constant';
720
+ interface DpeFormulaSymbol {
721
+ readonly name: string;
722
+ readonly description?: string;
723
+ /** `null`/assente quando il compilatore non sa mapparlo sui sei tipi logici: una mancanza
724
+ * dichiarata e' meglio di una bugia. */
725
+ readonly type?: ColumnType;
726
+ readonly kind: DpeFormulaSymbolKind;
501
727
  }
502
728
  /**
503
729
  * Riga di catalogo: identita' e fatti che l'ospite conosce **senza** caricare la definizione.
@@ -586,14 +812,66 @@ interface DpeColumnInfo {
586
812
  */
587
813
  isNullable: boolean;
588
814
  }
815
+ /**
816
+ * **Cio' che la libreria ha derivato su un nodo**: schema di uscita, compilabilita' e forma pretesa
817
+ * dai suoi siti di espressione. Arriva con **ogni** validazione, e da ADR 0041 con **una voce per
818
+ * ogni nodo della definizione, sempre** — anche per i nodi che il grafo non ha potuto ordinare.
819
+ *
820
+ * La presenza di una voce dice «questo nodo esiste, ed ecco cio' che la libreria ha potuto derivare
821
+ * su di esso»; **non** dice «il suo schema e' noto». Quello lo dice `hasSchema`, e solo quello.
822
+ */
589
823
  interface DpeNodeSchemaInfo {
590
824
  nodeName: string;
591
- columns?: DpeColumnInfo[];
825
+ /**
826
+ * Colonne di uscita. **Vuota non significa "nessuna colonna"** finche' non si e' letto
827
+ * `hasSchema`: e' vuota anche quando lo schema e' ignoto. Contarle senza guardare `hasSchema`
828
+ * afferma un fatto che il backend non ha affermato — ed e' il difetto misurato sul canvas prima
829
+ * dell'ADR 0041.
830
+ *
831
+ * **Obbligatoria**, come nel contratto (`contracts.md` §5): in C# e' `IReadOnlyList` mai nulla e
832
+ * arriva come `[]` quando e' vuota, quindi un ospite che omette la collezione vuota e' fuori
833
+ * contratto e non un caso da assecondare nel tipo. Dichiararla opzionale costringeva a un `?? []`
834
+ * a ogni lettura, e quel `?? []` e' **indistinguibile fra «vuota» e «non arrivata»** — cioe' la
835
+ * stessa ambiguita' che l'ADR 0041 ha tolto da `Columns`, riaperta un livello piu' in basso e in
836
+ * TypeScript. La regola generale (`contracts.md` §7): cio' che puo' mancare si dichiara opzionale
837
+ * **e** nullabile insieme, e una collezione non e' fra quelle cose.
838
+ */
839
+ columns: DpeColumnInfo[];
840
+ /**
841
+ * Il discriminante fra «schema derivato» e «schema ignoto» (ADR 0041).
842
+ *
843
+ * - `true` = `columns` e' un **fatto**. Vuota vuol dire davvero zero colonne — stato
844
+ * raggiungibile, e gia' diagnosticato con `DPE_SCHEMA_EMPTY`.
845
+ * - `false` = schema **ignoto**: la derivazione non e' arrivata a una risposta (fallita qui o a
846
+ * monte, oppure nodo dentro un ciclo). `columns` e' vuota e **non significa niente**.
847
+ *
848
+ * **Assente = `false`.** Un ospite che serializza omettendo i falsi non manda affatto la
849
+ * proprieta', e qui l'omissione coincide con la risposta prudente: e' il motivo per cui il campo
850
+ * si chiama `hasSchema` e non `isSchemaUnknown`. Chi legge confronta quindi con `=== true`, mai
851
+ * per veridicita', e non lo deduce da `columns.length` — dedurlo sarebbe rimettere in TypeScript
852
+ * la regola che questo campo esiste per portare.
853
+ */
854
+ hasSchema?: boolean;
592
855
  /**
593
856
  * `false` = nodo **valido ma non compilabile** (**I10**): e' un limite nostro, non un
594
857
  * errore dell'utente, e va reso diverso da un nodo invalido.
595
858
  */
596
859
  isCompilable: boolean;
860
+ /**
861
+ * La forma pretesa dai siti di espressione di questo nodo, oppure assente/`null` se il nodo non
862
+ * ne ha — che e' uno stato normale, non una mancanza.
863
+ *
864
+ * Sta qui e non sul risultato del catalogo perche' e' una cosa che la **libreria deriva** dal
865
+ * tipo del nodo (ADR 0031 §1), non una cosa che il **compilatore offre**: l'editor la riceve
866
+ * sempre, anche quando il catalogo non lo chiede affatto. Dedurla lato editor sarebbe una regola
867
+ * di dominio in TypeScript, che e' vietata; incrociarla con `DpeEnvironment.supportedForms`
868
+ * permette invece di **disabilitare** un campo che il compilatore registrato non compilera' mai.
869
+ *
870
+ * Opzionale **e** nullabile: un tipo di rispecchiamento descrive cio' che arriva **sul filo**, e
871
+ * l'ospite di riferimento omette i nulli come politica globale — quindi la proprieta' puo' non
872
+ * comparire affatto.
873
+ */
874
+ requiredForm?: DpeExpressionForm | null;
597
875
  }
598
876
  interface DpeWritebackStep {
599
877
  writebackName: string;
@@ -610,6 +888,23 @@ interface DpeWritebackStep {
610
888
  externalIdFieldName?: string;
611
889
  /** Presente se il writeback appartiene a un gruppo atomico. */
612
890
  atomicGroupName?: string;
891
+ /**
892
+ * Il valore **efficace** per `target === 'Database'` (ADR 0040): membro di un gruppo atomico ->
893
+ * `Atomic`, altrimenti il valore dichiarato sul nodo, altrimenti `PerRecord`.
894
+ *
895
+ * **Assente per `Json`/`Csv`**, e segue la regola comune a tutti i campi dello `Step` che
896
+ * istruiscono chi scrive — `operation`, `tableName`, `externalIdFieldName`,
897
+ * `processingGroupFieldName`, `tenantColumnName`: sono assenti quando l'ospite non scrive.
898
+ * L'assenza dice una cosa precisa, «questo non lo scrivi tu», e dirla e' meglio di un
899
+ * `PerRecord` che su un artefatto sarebbe pure falso: un file si scrive per intero o per niente.
900
+ *
901
+ * Non e' il campo del nodo con un altro nome. `WritebackNode.failureHandling` e' cio' che
902
+ * l'autore ha scritto, questo e' cio' che l'host deve fare: ricavarlo qui incrociando
903
+ * `atomicGroupName` con il valore dichiarato e con il default vorrebbe dire reimplementare tre
904
+ * regole di dominio nell'editor, che e' esattamente cio' che l'editor non fa. Se il dato serve,
905
+ * arriva di qui.
906
+ */
907
+ failureHandling?: WritebackFailureHandling;
613
908
  /**
614
909
  * Dichiarato, **non implementato dalla libreria**: il change tracking e' dell'host
615
910
  * (ADR 0011) e non influenza l'SQL generato. Va mostrato come una dichiarazione che l'host
@@ -673,12 +968,66 @@ interface DpeCompiledWriteback {
673
968
  /** Vedi {@link DpeFieldMappingInfo}: forma provvisoria. */
674
969
  targetMapping?: DpeFieldMappingInfo[];
675
970
  }
971
+ /**
972
+ * Il formato dell'artefatto prodotto. Due soli valori: `Database` non e' un artefatto e qui e'
973
+ * impossibile per costruzione — per questo il piano non riusa `WritebackTargetKind`.
974
+ */
975
+ type ArtifactKind = 'Json' | 'Csv';
976
+ /**
977
+ * Una colonna dell'artefatto, con i **due nomi** che l'ADR 0015 tiene distinti: `resultName`
978
+ * lega la colonna del result set, `headerName` e' l'unico che viene scritto nel file.
979
+ * Mostrarli come uno solo nasconderebbe proprio la divergenza che quell'ADR ha chiuso.
980
+ */
981
+ interface DpeArtifactColumn {
982
+ /** Alias SQL: serve a legare la colonna del result set. */
983
+ resultName: string;
984
+ /** Nome authored: e' quello che finisce nel file (ADR 0015). */
985
+ headerName: string;
986
+ type: LogicalType;
987
+ }
988
+ /**
989
+ * Il payload auto-sufficiente con cui l'ospite puo' **schedulare** la scrittura di un artefatto
990
+ * (ADR 0029): lo accoda, lo rilegge dopo un riavvio e lo riporta a `WriteArtifact`.
991
+ *
992
+ * L'editor non lo esegue e non lo materializza — `DpeBuilderApi` non acquista nessuna primitiva
993
+ * per questo — ma lo riceve dentro `DpeCompileResult.fileWritebacks`, e l'anteprima ne mostra
994
+ * l'SQL di lettura.
995
+ *
996
+ * `tenant` del record C# **non** e' qui, e non per dimenticanza: l'ambito tenant non attraversa
997
+ * il confine verso l'editor, per la stessa ragione per cui `getTable` reda la colonna di tenant
998
+ * (ADR 0027). Un backend che lo serializzi comunque non e' un errore: il client lo ignora.
999
+ */
1000
+ interface DpeArtifactPlan {
1001
+ /**
1002
+ * Timbro del formato del payload. Il piano puo' tornare indietro **vecchio** da una coda, e un
1003
+ * valore ignoto viene rifiutato dal backend invece che tollerato.
1004
+ */
1005
+ formatVersion: number;
1006
+ definitionName: string;
1007
+ /** E' anche il nome passato al sink dell'ospite: il piano non porta un `artifactName` distinto. */
1008
+ writebackName: string;
1009
+ sequence: number;
1010
+ kind: ArtifactKind;
1011
+ /** Lo legge l'ospite per scegliere la connessione, non la libreria. */
1012
+ dialect: SqlDialectKind;
1013
+ /** SQL di **lettura**: nessun artefatto e' stato prodotto. */
1014
+ statement: SqlStatement;
1015
+ columns?: DpeArtifactColumn[];
1016
+ /** Presenti solo per il `kind` corrispondente. */
1017
+ jsonOptions?: JsonArtifactOptions;
1018
+ csvOptions?: CsvArtifactOptions;
1019
+ }
676
1020
  interface DpeCompileResult {
677
1021
  hasErrors: boolean;
678
1022
  diagnostics?: Diagnostic[];
679
1023
  databaseWritebacks?: DpeCompiledWriteback[];
680
- /** SQL di lettura, non ancora eseguito. */
681
- fileWritebacks?: DpeCompiledWriteback[];
1024
+ /**
1025
+ * ADR 0029: **piani di artefatto**, non writeback compilati. Portano gia' kind, opzioni e
1026
+ * intestazioni authored, cioe' tutto cio' che serve a scrivere il file; il `step` non c'e'
1027
+ * perche' per un file sarebbe fatto di soli campi nulli. L'SQL di lettura non e' ancora stato
1028
+ * eseguito.
1029
+ */
1030
+ fileWritebacks?: DpeArtifactPlan[];
682
1031
  writebackSequence?: DpeWritebackStep[];
683
1032
  }
684
1033
 
@@ -699,14 +1048,14 @@ interface DpeCompileResult {
699
1048
  * l'editor la considera disponibile e mostra il comando attivo.
700
1049
  *
701
1050
  * **Dichiarazione sottrattiva (ADR 0020).** Da quando la libreria spedisce un client HTTP che
702
- * implementa tutte e dieci le primitive, l'identita' da sola non basta: chi eredita quel client
1051
+ * implementa tutte le primitive, l'identita' da sola non basta: chi eredita quel client
703
1052
  * non puo' dis-sovrascrivere un metodo. Disponibile diventa quindi «**sovrascritta** e **non
704
1053
  * elencata** in `unsupportedPrimitives`». La seconda meta' e' solo sottrattiva — non rende
705
1054
  * disponibile cio' che non e' implementato — e resta calcolata in questo file e in nessun altro.
706
1055
  */
707
1056
 
708
1057
  /** Le primitive che un ambiente ospite puo' legittimamente non offrire. */
709
- type DpeOptionalPrimitive = 'compilePreview' | 'load' | 'save' | 'getEnvironment' | 'listDefinitions' | 'createDefinition' | 'deleteDefinition';
1058
+ type DpeOptionalPrimitive = 'compilePreview' | 'load' | 'save' | 'getEnvironment' | 'getFormulaCatalog' | 'listDefinitions' | 'createDefinition' | 'deleteDefinition';
710
1059
  declare function dpeIsPrimitiveAvailable(api: DpeBuilderApi, primitive: DpeOptionalPrimitive): boolean;
711
1060
  /** L'insieme delle primitive disponibili: comodo per fotografarlo una volta alla costruzione. */
712
1061
  interface DpeCapabilities {
@@ -714,6 +1063,15 @@ interface DpeCapabilities {
714
1063
  readonly load: boolean;
715
1064
  readonly save: boolean;
716
1065
  readonly getEnvironment: boolean;
1066
+ /**
1067
+ * Il catalogo del linguaggio di formule (ADR 0036). **Condizione necessaria e non sufficiente**
1068
+ * per chiederlo: l'altra meta' e' `DpeEnvironment.providesFormulaCatalog`, che e' un fatto del
1069
+ * compilatore e non del trasporto. Le due stanno separate perche' sono due cose diverse — «il
1070
+ * backend non serve questa rotta» e «il compilatore non descrive il proprio linguaggio» — e
1071
+ * mescolarle renderebbe impossibile distinguere un ambiente incompleto da un compilatore
1072
+ * laconico.
1073
+ */
1074
+ readonly getFormulaCatalog: boolean;
717
1075
  readonly listDefinitions: boolean;
718
1076
  readonly createDefinition: boolean;
719
1077
  readonly deleteDefinition: boolean;
@@ -733,9 +1091,10 @@ interface DpeCommandAvailability {
733
1091
  * (`contracts.md` §7, normativo): `createDefinition` per scrivere, e `getEnvironment` perche' il
734
1092
  * dialetto della definizione nuova viene dall'ambiente (ADR 0017).
735
1093
  *
736
- * Perche' senza `getEnvironment` si disabilita invece di ripiegare su un dialetto qualsiasi: una
737
- * definizione creata per il dialetto sbagliato porta espressioni SQL native (ADR 0006) da
738
- * riscrivere tutte, e chiederlo all'utente e' proprio la scelta che l'ADR 0017 ha tolto. Un
1094
+ * Perche' senza `getEnvironment` si disabilita invece di ripiegare su un dialetto qualsiasi: il
1095
+ * dialetto decide con quali capacita' la definizione verra' compilata, e quali costrutti il
1096
+ * compilatore di formule copre (ADR 0031 §5: un dialetto fuori da `SupportedDialects` non compila
1097
+ * **nessuna** espressione), e chiederlo all'utente e' proprio la scelta che l'ADR 0017 ha tolto. Un
739
1098
  * comando disabilitato che dice perche' e' meglio di entrambe; il rimedio per l'ospite e' una
740
1099
  * riga, implementare `getEnvironment`.
741
1100
  *
@@ -799,6 +1158,14 @@ declare abstract class DpeBuilderApi {
799
1158
  *
800
1159
  * Prende la definizione **in lavorazione**, non quella salvata: cio' che l'editor mostra
801
1160
  * deve riferirsi a cio' che l'utente sta scrivendo. Va invocata con debounce.
1161
+ *
1162
+ * **`schemas` porta anche `requiredForm`**, la forma che i siti di espressione di quel nodo
1163
+ * pretendono. Sta li' e non sul risultato del catalogo delle formule perche' e' cio' che la
1164
+ * libreria **deriva** sul nodo, come le colonne e la compilabilita', mentre il catalogo e' cio'
1165
+ * che il compilatore **offre** e arriva solo quando il compilatore risponde: un ospite che
1166
+ * dichiara `providesFormulaCatalog` falso non fa chiamare quella rotta, e la forma non arrivava
1167
+ * mai. Chi implementa questo metodo la valorizza: senza, un campo formula non dice cosa vuole e
1168
+ * non si blocca quando il compilatore non sa produrre quella forma.
802
1169
  */
803
1170
  abstract validate(definition: DpeDefinition): Observable<DpeValidateResult>;
804
1171
  /**
@@ -830,7 +1197,7 @@ declare abstract class DpeBuilderApi {
830
1197
  * definizione che gli viene passata dall'ospite.
831
1198
  *
832
1199
  * La deserializzazione (`IDpeService.Deserialize`) resta del backend: qui arriva un
833
- * documento già letto, con le sue eventuali diagnostiche già emesse.
1200
+ * documento gia' letto, con le sue eventuali diagnostiche gia' emesse.
834
1201
  */
835
1202
  load(name: string): Observable<DpeDefinition>;
836
1203
  /** Salvataggio. Opzionale: un editor in sola lettura e' un uso legittimo. */
@@ -843,13 +1210,46 @@ declare abstract class DpeBuilderApi {
843
1210
  * Cosa l'editor fa con la risposta, e cosa non fa: mostra il dialetto in sola lettura e, se
844
1211
  * differisce da quello della definizione (ADR 0009: e' li' che vive, ed e' da li' che il
845
1212
  * backend lo legge), **lo segnala senza correggere**. Riscrivere `definition.dialect` sarebbe
846
- * una migrazione silenziosa di tutte le espressioni SQL native (ADR 0006), per giunta eseguita
1213
+ * una migrazione silenziosa delle capacita' con cui la definizione verra' compilata, per giunta eseguita
847
1214
  * all'apertura e capace di marcare come «modificata» una definizione che nessuno ha toccato.
848
1215
  *
849
1216
  * Opzionale come le altre: dove manca, l'editor mostra il dialetto della definizione e non
850
1217
  * dice nient'altro.
851
1218
  */
852
1219
  getEnvironment(): Observable<DpeEnvironment>;
1220
+ /**
1221
+ * `IDpeService.GetFormulaCatalog` — cosa il linguaggio di formule mette a disposizione **nel
1222
+ * nodo indicato** (ADR 0031/0036). Opzionale: senza, l'editor mostra un campo di testo semplice,
1223
+ * che e' esattamente cio' che mostrava prima che il catalogo esistesse.
1224
+ *
1225
+ * **Prende la definizione e il nome del nodo, non uno schema.** Il catalogo dipende dallo schema
1226
+ * a monte — i simboli `Column` sono le colonne che quel nodo vede — e risolvere uno schema e' del
1227
+ * backend (**I4**): il frontend non sa farlo e non deve imparare. La definizione e' quella **in
1228
+ * lavorazione**, perche' quella aperta nell'editor puo' non essere ancora salvata.
1229
+ *
1230
+ * **Non e' una chiamata leggera** (`frontend.md` §5-quater, normativo): lato libreria costa una
1231
+ * passata completa di grafo e di propagazione, e interroga il provider di metadati per tutti i
1232
+ * datasource della definizione. Chi la consuma la chiede **una volta per nodo** e la conserva —
1233
+ * `DpeFormulaCatalogStore` lo fa — e non a ogni apertura di un campo, che e' il modo naturale di
1234
+ * scriverlo e quello sbagliato.
1235
+ *
1236
+ * Si interroga `DpeEnvironment.providesFormulaCatalog` **prima** di chiamare: un compilatore che
1237
+ * non descrive il proprio linguaggio risponde un catalogo vuoto, e farsi pagare quella passata di
1238
+ * grafo per riceverlo e' spreco puro (ADR 0036 §5).
1239
+ *
1240
+ * **Restituisce l'involucro, non il catalogo nudo** (`contracts.md` §7). Il service distingue
1241
+ * tre esiti e il filo ne consegnava due, quindi un dialetto non coperto e un backend rotto
1242
+ * arrivavano qui identici: la differenza fra «non lo so» e «non si puo'» si perdeva prima di
1243
+ * raggiungere lo schermo. Chi implementa questo metodo non trasforma un esito con diagnostiche
1244
+ * in un errore di trasporto: le diagnostiche **sono** la risposta.
1245
+ *
1246
+ * **`requiredForm` non e' piu' in questa risposta**: sta su `DpeNodeSchemaInfo.requiredForm`,
1247
+ * cioe' negli schemi di `validate`. La ragione e' proprio la riga qui sopra — questa risposta
1248
+ * arriva solo quando il compilatore parla, e la forma la libreria la sa senza chiedere niente a
1249
+ * nessuno. Chi implementa questo metodo non la rimette qui: due copie dello stesso fatto
1250
+ * divergono (ADR 0018).
1251
+ */
1252
+ getFormulaCatalog(definition: DpeDefinition, nodeName: string): Observable<DpeFormulaCatalogResult>;
853
1253
  /**
854
1254
  * Elenco delle definizioni disponibili — **catalogo** (ADR 0019). Opzionale: dove manca, un
855
1255
  * catalogo montato dall'ospite mostra il perche' invece di un elenco vuoto.
@@ -891,7 +1291,7 @@ declare abstract class DpeBuilderApi {
891
1291
  *
892
1292
  * L'editor si comporta in base alla **categoria**, mai leggendo il messaggio: chi implementa
893
1293
  * {@link DpeBuilderApi} traduce l'errore di trasporto (status HTTP, payload, timeout) in un
894
- * `DpeApiError`, e da lì in poi nella libreria non esiste piu' nessuna nozione di HTTP
1294
+ * `DpeApiError`, e da li' in poi nella libreria non esiste piu' nessuna nozione di HTTP
895
1295
  * (ADR 0007).
896
1296
  */
897
1297
  /**
@@ -960,7 +1360,8 @@ declare const DPE_API_ERROR_FALLBACK_MESSAGE: Record<DpeApiErrorCategory, string
960
1360
  * nessuna cache, nessun debounce, nessuna intestazione propria. Traduce trasporto ed errori e
961
1361
  * nient'altro — la cache vive negli store, il debounce nel chiamante, i tentativi e
962
1362
  * l'autenticazione negli interceptor dell'ospite. E non tocca `definition.dialect` in nessun
963
- * metodo (ADR 0009 e 0017): sarebbe una migrazione silenziosa delle espressioni SQL native.
1363
+ * metodo (ADR 0009 e 0017): sarebbe una migrazione silenziosa delle capacita' con cui il backend
1364
+ * compilera' la definizione.
964
1365
  */
965
1366
 
966
1367
  /**
@@ -973,7 +1374,7 @@ interface DpeBuilderHttpConfig {
973
1374
  /**
974
1375
  * Primitive opzionali che questo ambiente **non serve** (`contracts.md` §7, dichiarazione
975
1376
  * sottrattiva). E' l'unico modo che ha l'ospite di spegnere una primitiva che questo client
976
- * implementa per forza: conoscendo tutti e dieci gli endpoint, li dichiarerebbe altrimenti tutti
1377
+ * implementa per forza: conoscendo tutti e undici gli endpoint, li dichiarerebbe altrimenti tutti
977
1378
  * disponibili, e un comando attivo su un endpoint non servito fallisce alla pressione.
978
1379
  */
979
1380
  unsupported?: readonly DpeOptionalPrimitive[];
@@ -990,7 +1391,7 @@ declare class HttpDpeBuilderApi extends DpeBuilderApi {
990
1391
  */
991
1392
  readonly unsupportedPrimitives: readonly DpeOptionalPrimitive[];
992
1393
  /**
993
- * Composizione dell'URL. Sovrascriverlo basta a spostare tutte e dieci le rotte sotto un altro
1394
+ * Composizione dell'URL. Sovrascriverlo basta a spostare tutte e undici le rotte sotto un altro
994
1395
  * prefisso senza toccare un metodo.
995
1396
  *
996
1397
  * `?? ''` e non un default: `baseUrl: ''` e' una configurazione **valida** e significa «rotte
@@ -1053,6 +1454,13 @@ declare class HttpDpeBuilderApi extends DpeBuilderApi {
1053
1454
  protected httpPost<T>(path: string, body: unknown): Observable<T>;
1054
1455
  protected httpPut<T>(path: string, body: unknown): Observable<T>;
1055
1456
  protected httpDelete<T>(path: string): Observable<T>;
1457
+ /**
1458
+ * La rotta della validazione. Dal trasloco di `requiredForm` i suoi `schemas` portano **tre**
1459
+ * fatti per nodo e non due — colonne, compilabilita' e forma richiesta dai siti di espressione —
1460
+ * e un ospite che serva questa rotta a mano deve valorizzare anche il terzo: e' l'unica strada
1461
+ * per cui la forma arriva all'editor, e senza di essa un campo formula non dice cosa vuole ne'
1462
+ * si blocca quando il compilatore non sa produrla.
1463
+ */
1056
1464
  validate(definition: DpeDefinition): Observable<DpeValidateResult>;
1057
1465
  getTables(): Observable<TableSummary[]>;
1058
1466
  getTable(tableName: string): Observable<TableLookupResult>;
@@ -1113,6 +1521,36 @@ declare class HttpDpeBuilderApi extends DpeBuilderApi {
1113
1521
  * senza correggere se differisce da quello della definizione.
1114
1522
  */
1115
1523
  getEnvironment(): Observable<DpeEnvironment>;
1524
+ /**
1525
+ * L'**undicesima rotta** (ADR 0036): `POST {base}/formula-catalog/{nodeName}`, corpo il documento
1526
+ * nudo. Le altre dieci non cambiano.
1527
+ *
1528
+ * Perche' un `POST` e non un `GET`: il catalogo dipende dallo **schema a monte** del nodo, che il
1529
+ * backend sa risolvere solo avendo la definizione, e la definizione aperta nell'editor puo' non
1530
+ * essere ancora salvata. Un `GET` con il solo nome del nodo risponderebbe sul documento
1531
+ * archiviato, cioe' su un altro documento.
1532
+ *
1533
+ * Perche' il nome del nodo sta nel **percorso** e non nel corpo: un involucro
1534
+ * `{ definition, nodeName }` e' esattamente l'errore silenzioso del contratto — un backend che
1535
+ * deserializza una `DpeDefinition` da `{definition: …}` non riconosce nessuna proprieta',
1536
+ * risponde `200`, e l'editor riceve il catalogo di una definizione vuota. Meglio una rotta che
1537
+ * non puo' sbagliare che un secondo corpo con involucro.
1538
+ *
1539
+ * **La risposta e' `DpeFormulaCatalogResult`, non `DpeFormulaCatalog`** (`contracts.md` §7-bis).
1540
+ * E' l'unica correzione di questa rotta: consegnava il catalogo nudo, quindi i tre esiti del
1541
+ * service ne diventavano due e un dialetto non coperto si presentava come un guasto di rete. Il
1542
+ * client non interpreta niente di cio' che riceve — la tricotomia si legge in
1543
+ * `dpeFormulaCatalogOutcome`, dove e' pura e verificabile.
1544
+ *
1545
+ * **Rottura dichiarata del contratto di rotta:** la risposta non porta piu' `requiredForm`. La
1546
+ * forma richiesta dai siti di espressione di un nodo sta ora su `DpeNodeSchemaInfo.requiredForm`,
1547
+ * cioe' negli schemi di `POST {base}/validate`. Un ospite che la serializzi ancora qui non rompe
1548
+ * niente — il client passa il corpo intero e nessuno la legge — ma resta l'unica copia di un
1549
+ * fatto che l'editor prende da un'altra parte. Il motivo del trasloco e' che questa rotta
1550
+ * l'editor non la chiama affatto quando `DpeEnvironment.providesFormulaCatalog` e' falso: la
1551
+ * forma non arrivava mai, proprio dagli ospiti piu' laconici.
1552
+ */
1553
+ getFormulaCatalog(definition: DpeDefinition, nodeName: string): Observable<DpeFormulaCatalogResult>;
1116
1554
  /** Nessun parametro di interrogazione: il filtro del catalogo e' locale, di proposito. */
1117
1555
  listDefinitions(): Observable<DpeDefinitionSummary[]>;
1118
1556
  /**
@@ -1198,9 +1636,10 @@ declare class DpeCatalogStore {
1198
1636
  * contratto, e non deve esistere — si comporrebbe di queste due comunque, e una primitiva
1199
1637
  * dedicata dovrebbe ridecidere lato host cosa cambia.
1200
1638
  *
1201
- * Il dialetto e' quello della **definizione di partenza**, non quello dell'ambiente: le
1202
- * espressioni sono SQL nativo (ADR 0006) e cambiare dialetto duplicando sarebbe una migrazione
1203
- * silenziosa.
1639
+ * Il dialetto e' quello della **definizione di partenza**, non quello dell'ambiente: cambiarlo
1640
+ * duplicando sarebbe una migrazione silenziosa: il dialetto decide le capacita' con cui si
1641
+ * compila, e se il compilatore di formule non lo copre la copia non compila nessuna espressione
1642
+ * (ADR 0031 §5).
1204
1643
  */
1205
1644
  duplicate(sourceName: string, name: string, label: string): Observable<DpeDefinitionSummary>;
1206
1645
  /** Cancella per nome e ricarica l'elenco. La conferma e' della schermata, non dello store. */
@@ -1220,6 +1659,215 @@ declare class DpeCatalogStore {
1220
1659
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<DpeCatalogStore>;
1221
1660
  }
1222
1661
 
1662
+ /**
1663
+ * Le condizioni dei campi condizionali, **in un punto solo**.
1664
+ *
1665
+ * Un campo condizionale e' un campo del modello che ha significato solo quando un altro campo del
1666
+ * **suo stesso nodo** — il discriminante — vale una certa cosa: `jsonOptions` solo con
1667
+ * `target === 'Json'`, `expressionFields` solo con `kind` diverso da `Slice`, e cosi' via. Le
1668
+ * condizioni sono usate dall'ispettore in due direzioni opposte:
1669
+ *
1670
+ * 1. **resa** (`frontend.md` §5-ter, normativa): il controllo si rende quando la condizione vale
1671
+ * **oppure** quando il campo porta un valore. Un valore fuori condizione che nessun controllo
1672
+ * mostra non e' cancellabile dall'editor, e per **I7** sopravvive a ogni salvataggio;
1673
+ * 2. **ripulitura**: cambiare il discriminante e' un gesto deliberato con cui l'autore dichiara
1674
+ * inapplicabili i campi che il valore nuovo non governa, e quei campi escono dal documento.
1675
+ *
1676
+ * Fino a LS9 le stesse condizioni erano scritte **due volte in ogni ispettore**, una per direzione,
1677
+ * a pochi metodi di distanza. E' la duplicazione piu' facile da introdurre e la piu' difficile da
1678
+ * vedere, perche' i sintomi di una divergenza sono silenziosi e nessun test li coglie:
1679
+ *
1680
+ * - un campo **ripulito che resta mostrato** — la ripulitura lo toglie, la resa lo rimette, e
1681
+ * l'utente vede un controllo che non corrisponde a niente nel documento;
1682
+ * - §5-ter che **smette di coprire un campo** — la resa lo nasconde mentre il documento lo porta,
1683
+ * cioe' il difetto che quella regola esiste per chiudere, tornato in silenzio.
1684
+ *
1685
+ * Con la tabella qui sotto le due direzioni leggono **la stessa riga**: `dpeFieldVisibility()`
1686
+ * costruisce un segnale per ogni voce, `dpePruneInapplicable()` scorre le voci una per una.
1687
+ * Aggiungere un campo condizionale domani significa scrivere **una** riga; scriverla per la resa e
1688
+ * dimenticarla per la ripulitura non e' possibile, perche' e' la stessa riga.
1689
+ *
1690
+ * ## Cio' che questo file NON chiude, e va detto
1691
+ *
1692
+ * **La fonte autorevole di queste condizioni e' il backend**, e resta ricopiata a mano:
1693
+ * `dpe/dpe/Validation/ModelRules.cs` e `dpe/dpe/Validation/WritebackRules.cs`. Qui resta una
1694
+ * **regola di dominio in TypeScript**, cioe' una deroga dichiarata a un vincolo del progetto
1695
+ * (`frontend.md` §5-ter, «duplicazione dichiarata e temporanea»). `npm run check:modelli` **non**
1696
+ * la copre: confronta le forme dei tipi, non le condizioni.
1697
+ *
1698
+ * Quindi: chi tocca una condizione di la' deve toccarla anche di qua, e i due sintomi silenziosi
1699
+ * elencati sopra valgono identici per una divergenza dal backend — con l'aggravante che li' non
1700
+ * c'e' nemmeno il compilatore. La direzione che chiude la classe invece di sorvegliarla (la
1701
+ * tabella come **dato** pubblicato dal contratto, letta da `ModelRules`) e' la questione aperta 32.
1702
+ *
1703
+ * ## Cosa non sta in tabella, e perche'
1704
+ *
1705
+ * Solo i campi **del nodo**: la ripulitura toglie chiavi dal nodo, quindi una voce deve essere una
1706
+ * chiave del nodo. Una condizione che governa un campo **dentro una riga di una collezione** (il
1707
+ * tipo dichiarato di un campo di sorgente) non e' rappresentabile qui e resta scritta nel suo
1708
+ * ispettore, dove la meta' «porta un valore» e' un `some(...)` sulle righe.
1709
+ */
1710
+
1711
+ /** La condizione di applicabilita' di un campo, valutata sul nodo intero. */
1712
+ type DpeFieldCondition<TNode> = (node: TNode) => boolean;
1713
+ /**
1714
+ * La tabella di un tipo di nodo: **chiave del nodo → condizione**.
1715
+ *
1716
+ * Le chiavi sono limitate a `keyof TNode` cosi' un campo rinominato nel modello non lascia qui una
1717
+ * riga orfana che nessuno consuma, e la ripulitura non puo' togliere una chiave inventata.
1718
+ */
1719
+ type DpeConditionalFields<TNode> = {
1720
+ readonly [K in keyof TNode]?: DpeFieldCondition<TNode>;
1721
+ };
1722
+ /** Un segnale di visibilita' per ogni voce della tabella, con lo stesso nome del campo. */
1723
+ type DpeFieldVisibility<TConditions> = {
1724
+ readonly [K in keyof TConditions]: Signal<boolean>;
1725
+ };
1726
+ /**
1727
+ * «Il campo porta un valore», nel senso di `frontend.md` §5-ter.
1728
+ *
1729
+ * Nessuna delle equivalenze qui sotto e' un giudizio sul valore — dire che e' sbagliato tocca al
1730
+ * backend, e la regola di resa vale **diagnostica o no**:
1731
+ *
1732
+ * - **stringa vuota = assente**, perche' il backend confronta con `string.IsNullOrEmpty`: un
1733
+ * `processingGroupFieldName: ''` arrivato da fuori non deve far comparire un campo vuoto, che
1734
+ * sarebbe il rumore che la regola promette di non introdurre;
1735
+ * - **`false` = assente**, perche' i campi governati sono `bool` **non nullable** con default
1736
+ * `false` lato C# (`OnlyChangedRows`, `AllowsMultipleLookupValues`): dopo la deserializzazione
1737
+ * `false` e' indistinguibile dall'assenza;
1738
+ * - **collezione vuota = assente**: un `criteria: []` non dichiara niente, e il backend lo conta
1739
+ * con `Count(...) == 0`.
1740
+ *
1741
+ * Un oggetto invece **e' sempre** una dichiarazione, anche `{}`: per il backend un `jsonOptions`
1742
+ * non nullo fuori dal proprio target e' `DPE_MODEL_CONDITIONAL_FORBIDDEN` qualunque cosa contenga.
1743
+ */
1744
+ declare function dpeDeclares(value: unknown): boolean;
1745
+ /**
1746
+ * I segnali di resa di §5-ter: **la condizione vale oppure il campo porta un valore**.
1747
+ *
1748
+ * Si costruiscono dalla tabella intera e non uno per uno, cosi' il segnale di un campo nuovo esiste
1749
+ * per il solo fatto che la sua riga esiste. Nel template il tipo fa il resto: `shows.jsonOptions()`
1750
+ * su una voce che non c'e' non compila, quindi non si puo' nascondere un campo per distrazione.
1751
+ */
1752
+ declare function dpeFieldVisibility<TNode extends object, TConditions extends DpeConditionalFields<TNode>>(node: Signal<TNode>, conditions: TConditions): DpeFieldVisibility<TConditions>;
1753
+ /**
1754
+ * La modifica di un discriminante, **piu'** la rimozione dei campi che con il valore nuovo non si
1755
+ * applicano piu'.
1756
+ *
1757
+ * La condizione si valuta sul nodo **come sara' dopo il gesto** (`{ ...node, ...change }`), non su
1758
+ * quello di adesso: e' il solo modo di trattare un discriminante che ne cambia un altro nello
1759
+ * stesso gesto — su un writeback la destinazione decide l'operazione, e l'operazione decide il
1760
+ * campo di identificazione esterna.
1761
+ *
1762
+ * E si ripete **finche' non si stabilizza**, perche' una rimozione puo' invalidare la condizione
1763
+ * di un altro campo: portando una scrittura `Upsert` da `Database` a `Json`, il primo giro toglie
1764
+ * `operation` e solo il secondo si accorge che `externalIdFieldName` non e' piu' governato da
1765
+ * niente. Con un giro solo quel valore restava nel documento su un artefatto, dove il backend
1766
+ * **non lo diagnostica**: ignorato e invisibile, il caso peggiore. Trovato **eseguendo** la demo,
1767
+ * non leggendo il codice — la versione a un giro passava tutti i test che c'erano, e il test che
1768
+ * la coglie e' stato scritto dopo averla vista fallire a schermo.
1769
+ *
1770
+ * Il punto fisso esiste sempre: ogni giro puo' solo **aggiungere** rimozioni, i campi sono finiti
1771
+ * e un campo tolto non torna. Una condizione scritta al contrario (vera **perche'** l'altro campo
1772
+ * e' assente) renderebbe il risultato dipendente dall'ordine: in tabella non ce ne sono, e questo
1773
+ * e' il motivo per cui non ce ne devono essere.
1774
+ *
1775
+ * **Si toglie cio' che non si applica, non cio' che apparteneva al valore precedente**, e la
1776
+ * differenza non e' teorica: `Expression` → `ComputeRelative` non tocca `expressionFields`, perche'
1777
+ * quel campo e' governato da entrambi. Un «cambiando tipo si azzera» sarebbe piu' semplice da
1778
+ * scrivere e cancellerebbe espressioni SQL su un passaggio che non le rende inapplicabili.
1779
+ *
1780
+ * Togliere e' **rimuovere la chiave** (`undefined`), non scriverci `false` o `[]`: le due forme
1781
+ * sono equivalenti per il validatore e diverse per il documento, e il documento e' cio' che si
1782
+ * salva (**I7**).
1783
+ *
1784
+ * Si rimuove **solo cio' che c'e'**: un campo gia' assente non entra nel patch. Sul documento
1785
+ * salvato non cambia niente — una chiave a `undefined` sparisce serializzando — ma il patch
1786
+ * diventa il resoconto esatto del gesto, e «questo cambio non tocca niente» diventa una cosa
1787
+ * osservabile invece di una cosa da credere.
1788
+ *
1789
+ * Non e' distruttivo perche' il patch passa da `DpeDocumentStore.updateNode` → `commit`, che mette
1790
+ * l'istantanea precedente nella cronologia: «Annulla» rimette tutto. Verificato a schermo in
1791
+ * LS7-quater, non dedotto — era il solo fatto che avrebbe potuto togliere la ragione a questo
1792
+ * comportamento.
1793
+ */
1794
+ declare function dpePruneInapplicable<TNode extends object, TConditions extends DpeConditionalFields<TNode>>(node: TNode, change: Partial<TNode>, conditions: TConditions): Partial<TNode>;
1795
+ /**
1796
+ * Sorgente: il tipo decide da dove si legge (`ModelRules.cs`, `ApplyDataSources`).
1797
+ *
1798
+ * Nessuno dei tre e' diagnosticato **fuori** condizione — il backend li richiede dove servono e
1799
+ * ignora il resto — e non cambia niente: §5-ter guarda il documento, non l'elenco dei codici.
1800
+ */
1801
+ declare const DPE_DATA_SOURCE_CONDITIONS: {
1802
+ tableName: (node: DataSourceNode) => boolean;
1803
+ csvOptions: (node: DataSourceNode) => boolean;
1804
+ externalDatasetName: (node: DataSourceNode) => boolean;
1805
+ };
1806
+ /**
1807
+ * Filtro: `isDynamic` sceglie quale meta' del nodo vale (`ModelRules.cs`, `ApplyFilters`).
1808
+ *
1809
+ * Il parametro serve al filtro dinamico; criteri e condizione a quello statico.
1810
+ */
1811
+ declare const DPE_FILTER_CONDITIONS: {
1812
+ criteria: (node: FilterNode) => boolean;
1813
+ condition: (node: FilterNode) => boolean;
1814
+ filterParameterName: (node: FilterNode) => boolean;
1815
+ };
1816
+ /**
1817
+ * Giunzione: la molteplicita' ammessa ha significato solo su una `Lookup`
1818
+ * (`JoinRules.cs`, `DialectRules.cs`).
1819
+ */
1820
+ declare const DPE_JOIN_CONDITIONS: {
1821
+ allowsMultipleLookupValues: (node: JoinNode) => boolean;
1822
+ };
1823
+ /** Percorso gerarchico: le aggregazioni servono quando sono dichiarate richieste. */
1824
+ declare const DPE_HIERARCHY_PATH_CONDITIONS: {
1825
+ aggregateFields: (node: HierarchyPathNode) => boolean;
1826
+ };
1827
+ /**
1828
+ * Trasformazione: `kind` governa i quattro campi (`ModelRules.cs`, `ApplyTransforms`).
1829
+ *
1830
+ * `expressionFields` e' governato da **due** tipi, ed e' il motivo per cui la ripulitura non puo'
1831
+ * essere un azzeramento.
1832
+ */
1833
+ declare const DPE_TRANSFORM_CONDITIONS: {
1834
+ expressionFields: (node: TransformNode) => boolean;
1835
+ droppedFields: (node: TransformNode) => boolean;
1836
+ partitionBy: (node: TransformNode) => boolean;
1837
+ orderBy: (node: TransformNode) => boolean;
1838
+ };
1839
+ /**
1840
+ * Scrittura: `target` governa sei campi, **`operation` ne governa un settimo**
1841
+ * (`ModelRules.cs`, `ApplyWritebacks`; `WritebackRules.cs`, `CheckArtifactOptions`,
1842
+ * `CheckProcessingGroupField`, `CheckFailureHandling`).
1843
+ *
1844
+ * `tableName` e `onlyChangedRows` sono in tabella pur **non** essendo diagnosticati fuori da
1845
+ * `Database`: nessuna regola li vieta, quindi il valore non e' «invalido», e' **ignorato e
1846
+ * invisibile** — che e' peggio, perche' niente lo segnala e un cambio di destinazione lo puo'
1847
+ * rendere attivo di colpo. Far dipendere questa tabella dall'elenco dei codici diagnostici
1848
+ * accoppierebbe l'ispettore a un'altra regola di dominio ancora.
1849
+ *
1850
+ * `externalIdFieldName` dipende da `operation`, **non** da `target`: e' la condizione che il
1851
+ * backend applica (`Operation == Upsert`, richiesto li' e vietato altrove) ed e' la sola scritta
1852
+ * qui. Fino a LS9 la ripulitura ne usava una seconda, piu' larga (`Target == Database`): era
1853
+ * proprio la divergenza interna che questo file esiste per rendere impossibile.
1854
+ *
1855
+ * `failureHandling` e' vietato dal backend anche dentro un gruppo atomico, e qui non si dice: la
1856
+ * condizione di resa piu' larga fa comparire il controllo — con il rilievo sotto — invece di
1857
+ * nascondere un valore che l'autore dovrebbe poter togliere. Restringerla farebbe sparire il
1858
+ * controllo proprio dove serve.
1859
+ */
1860
+ declare const DPE_WRITEBACK_CONDITIONS: {
1861
+ tableName: (node: WritebackNode) => boolean;
1862
+ operation: (node: WritebackNode) => boolean;
1863
+ externalIdFieldName: (node: WritebackNode) => boolean;
1864
+ onlyChangedRows: (node: WritebackNode) => boolean;
1865
+ processingGroupFieldName: (node: WritebackNode) => boolean;
1866
+ failureHandling: (node: WritebackNode) => boolean;
1867
+ jsonOptions: (node: WritebackNode) => boolean;
1868
+ csvOptions: (node: WritebackNode) => boolean;
1869
+ };
1870
+
1223
1871
  /**
1224
1872
  * Il grafo della definizione: **un solo posto** costruisce gli id di nodi, porte e archi, e
1225
1873
  * **un solo elenco** descrive dove vivono i riferimenti fra nodi.
@@ -1228,7 +1876,7 @@ declare class DpeCatalogStore {
1228
1876
  * derivazione degli archi dall'altro) fa sparire un arco **senza nessun errore**: e' il
1229
1877
  * difetto piu' difficile da trovare in un editor a canvas. Allo stesso modo, un riferimento
1230
1878
  * dimenticato nell'elenco degli slot fa restare incoerente il documento dopo una rinomina,
1231
- * anche lì in silenzio.
1879
+ * anche li' in silenzio.
1232
1880
  *
1233
1881
  * Cosa **non** sta qui: nessuna regola di dominio. Questo file dice *dove* stanno i nomi dei
1234
1882
  * nodi a monte, non se un riferimento e' valido, se il grafo ha cicli (**I2**), se un nodo e'
@@ -1285,7 +1933,16 @@ interface DpeSourceSlot<TNode> {
1285
1933
  read(node: TNode): readonly (string | undefined)[];
1286
1934
  write(node: TNode, names: readonly (string | undefined)[]): TNode;
1287
1935
  }
1288
- /** Gli slot di ogni collezione. Aggiungere un nodo significa aggiungere una riga qui. */
1936
+ /**
1937
+ * Gli slot di ogni collezione. Aggiungere un nodo significa aggiungere una riga qui.
1938
+ *
1939
+ * **Che ci sia una riga per ogni collezione lo garantisce il compilatore**, non un test: il tipo
1940
+ * e' mappato sull'unione `DpeNodeCollectionName`, quindi una collezione aggiunta al modello e
1941
+ * dimenticata qui ferma la build («Property '...' is missing»), e `DPE_NODE_COLLECTIONS`, con cui
1942
+ * il documento si cammina, e' a sua volta controllato totale. Il test che lo verificava a runtime
1943
+ * non poteva fallire, e per questo e' stato tolto: aggiungeva la convinzione di una copertura, non
1944
+ * la copertura.
1945
+ */
1289
1946
  declare const DPE_SOURCE_SLOTS: {
1290
1947
  readonly [K in DpeNodeCollectionName]: readonly DpeSourceSlot<DpeNodeCollectionMap[K]>[];
1291
1948
  };
@@ -1368,7 +2025,7 @@ declare function dpeWriteSourceReference<K extends DpeNodeCollectionName>(collec
1368
2025
  * avere.
1369
2026
  *
1370
2027
  * Cosa **non** fa, di proposito: non rinomina gli **alias di colonna** (sono un altro spazio
1371
- * di nomi) e non decide se il nuovo nome sia lecito o già usato — l'unicita' e' **I1**, la
2028
+ * di nomi) e non decide se il nuovo nome sia lecito o gia' usato — l'unicita' e' **I1**, la
1372
2029
  * verifica il backend.
1373
2030
  *
1374
2031
  * Il confronto e' **esatto**, non case-insensitive: `domain-model.md` dichiara il confronto
@@ -1402,6 +2059,19 @@ declare function dpeCountReferences(definition: DpeDefinition, nodeName: string)
1402
2059
  declare function dpeDiagnosticNodeName(diagnostic: Diagnostic, definition?: DpeDefinition): string | undefined;
1403
2060
  /** Il campo in causa, per evidenziarlo nell'ispettore. */
1404
2061
  declare function dpeDiagnosticField(diagnostic: Diagnostic): string | undefined;
2062
+ /**
2063
+ * La diagnostica riguarda **quella riga** di una collezione dentro il nodo, e quel campo.
2064
+ *
2065
+ * Serve dove un nodo ha piu' righe con lo stesso nome di campo — il caso reale sono le colonne
2066
+ * calcolate di una trasformazione, che hanno tutte un `expression`. Filtrare per solo nome di
2067
+ * campo, come fa `issuesOn`, mostrerebbe l'errore della prima formula sotto la terza: il rilievo
2068
+ * arriva accanto a un testo che non lo ha prodotto, ed e' peggio di non mostrarlo.
2069
+ *
2070
+ * Il confronto e' sul segmento del percorso che nomina la collezione, ovunque stia: `contracts.md`
2071
+ * §1 pubblica il percorso in **due** forme (col nome del nodo dalla validazione, col solo indice
2072
+ * dalla deserializzazione), e in entrambe il segmento della riga porta l'indice.
2073
+ */
2074
+ declare function dpeDiagnosticTargetsItem(diagnostic: Diagnostic, collection: string, index: number, field: string): boolean;
1405
2075
  /**
1406
2076
  * `true` per l'unico codice che significa "hai fatto bene, siamo noi" (**I10**, ADR 0005):
1407
2077
  * `Forecast`, `CustomNode`, costrutto non supportato dal dialetto scelto. Non va mescolato
@@ -1695,6 +2365,326 @@ declare class DpeDocumentStore {
1695
2365
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<DpeDocumentStore>;
1696
2366
  }
1697
2367
 
2368
+ /**
2369
+ * La lettura dei **tre esiti** del catalogo delle formule — `contracts.md` §7, normativo.
2370
+ *
2371
+ * Sta in una funzione pura e non in un `if` dentro un componente per la ragione che ha reso questo
2372
+ * lotto necessario: la versione precedente del contratto consegnava il catalogo **nudo**, quindi i
2373
+ * tre esiti del service ne diventavano due, e *dialetto non coperto* e *backend rotto* arrivavano
2374
+ * a schermo identici. Un degrado silenzioso non si vede rileggendo un componente; si vede
2375
+ * scrivendo una tabella e provandola.
2376
+ *
2377
+ * **Il discriminante e' `diagnostics`, non `catalog`.** E' la riga che vale piu' di tutte le
2378
+ * altre, perche' la stesura precedente diceva il contrario: con `ProvidesCatalog == false` il
2379
+ * catalogo arriva **presente e vuoto**, con il nome del linguaggio e zero diagnostiche — quindi
2380
+ * un editor che ramasse su `catalog == null` non entrerebbe mai in quel caso, e mostrerebbe un
2381
+ * fallimento dove non c'e' niente da segnalare.
2382
+ *
2383
+ * `catalog` nullo o assente significa **una cosa sola: non e' stato prodotto**.
2384
+ */
2385
+
2386
+ /**
2387
+ * I quattro stati in cui il campo formula puo' trovarsi rispetto al catalogo — tre del contratto
2388
+ * piu' «non lo so ancora», che e' quello in cui il campo nasce.
2389
+ *
2390
+ * Unione discriminata e non un oggetto con quattro campi opzionali: cosi' «fallito **e** con
2391
+ * tavolozza» non e' rappresentabile, e chi rende non deve decidere quale dei due vince.
2392
+ */
2393
+ type DpeFormulaCatalogOutcome =
2394
+ /** Nessuna risposta conservata: non e' stato chiesto, e' in volo, o la richiesta e' fallita. */
2395
+ {
2396
+ readonly kind: 'Unknown';
2397
+ }
2398
+ /** Catalogo consegnato **con contenuto**: si mostra la tavolozza. */
2399
+ | {
2400
+ readonly kind: 'Palette';
2401
+ readonly catalog: DpeFormulaCatalog;
2402
+ }
2403
+ /**
2404
+ * Catalogo consegnato **vuoto** e nessuna diagnostica: il compilatore non descrive il proprio
2405
+ * linguaggio, che non e' un errore. Niente tavolozza e **nessun rumore**; `languageName` c'e' ed
2406
+ * e' l'unica cosa da mostrare — e l'etichetta del campo la prende comunque dall'ambiente.
2407
+ */
2408
+ | {
2409
+ readonly kind: 'Silent';
2410
+ readonly languageName?: string;
2411
+ }
2412
+ /**
2413
+ * Diagnostiche non vuote: il catalogo non e' stato prodotto e **il perche' si mostra**.
2414
+ *
2415
+ * `lead` e' la riga in testa, `details` tutto il resto **nell'ordine ricevuto**. La separazione
2416
+ * non e' estetica: il sacco strutturale riguarda l'intera definizione e puo' contenere voci che
2417
+ * con il nodo richiesto non c'entrano, filtrarle per pertinenza non e' affidabile (l'errore che
2418
+ * spiega lo schema puo' stare a piu' salti di distanza), quindi il rimedio dichiarato e' una
2419
+ * riga in testa e il resto come dettaglio.
2420
+ */
2421
+ | {
2422
+ readonly kind: 'Failed';
2423
+ readonly lead: Diagnostic;
2424
+ readonly details: readonly Diagnostic[];
2425
+ readonly hasError: boolean;
2426
+ };
2427
+ /**
2428
+ * Legge l'involucro e dice in quale dei quattro stati ci si trova.
2429
+ *
2430
+ * L'ordine dei controlli e' il contratto messo in fila, e non e' intercambiabile:
2431
+ *
2432
+ * 1. nessun risultato -> `Unknown`;
2433
+ * 2. **diagnostiche non vuote** -> `Failed`, indipendentemente da `catalog`;
2434
+ * 3. catalogo con contenuto -> `Palette`;
2435
+ * 4. tutto il resto -> `Silent`, cioe' niente tavolozza e nessun rumore.
2436
+ *
2437
+ * Il quarto ramo assorbe anche il caso fuori contratto «nessun catalogo e nessuna diagnostica»:
2438
+ * a schermo e' indistinguibile dal terzo esito — niente da mostrare e niente da segnalare — e
2439
+ * inventare un quinto stato per rimproverare il backend darebbe all'utente un messaggio su cui non
2440
+ * puo' agire.
2441
+ */
2442
+ declare function dpeFormulaCatalogOutcome(result: DpeFormulaCatalogResult | undefined): DpeFormulaCatalogOutcome;
2443
+ /**
2444
+ * L'etichetta con cui si nomina all'utente la forma pretesa dal campo.
2445
+ *
2446
+ * E' **traduzione**, non deduzione: la forma arriva dal backend, qui si sceglie solo come
2447
+ * chiamarla in italiano. Dedurla dal tipo di nodo sarebbe la regola di dominio che il contratto
2448
+ * vieta, e la differenza fra le due cose e' tutta in questa riga.
2449
+ */
2450
+ declare function dpeExpressionFormLabel(form: DpeExpressionForm | null | undefined): string | undefined;
2451
+ /**
2452
+ * La stessa cosa detta all'utente: «serve un valore», «serve una funzione di finestra».
2453
+ *
2454
+ * Esiste separata dall'etichetta nuda per una ragione banale e reale: **l'articolo dipende dal
2455
+ * genere**, e comporre «serve un » + etichetta nel template produce «serve un funzione di
2456
+ * finestra». Il template non puo' sapere il genere di una parola, questa funzione si'.
2457
+ */
2458
+ declare function dpeExpressionFormPrompt(form: DpeExpressionForm | null | undefined): string | undefined;
2459
+ /**
2460
+ * L'incrocio fra **la forma richiesta dal nodo** e **le forme che il compilatore sa compilare**.
2461
+ *
2462
+ * E' la meta' «disabilitare» della funzione che il contratto prescriveva: la meta' «mostrare» —
2463
+ * la pastiglia «serve una funzione di finestra» — era implementabile da LF6, perche' il primo
2464
+ * operando arriva con il catalogo; il secondo non stava sul filo, e senza di esso l'editor poteva
2465
+ * solo dire cosa serve, mai che non si potra' avere.
2466
+ *
2467
+ * Stessa forma di `DpeCommandAvailability` (`dpe-capabilities.ts`) e per la stessa ragione: un
2468
+ * campo spento che non dice perche' manda a cercare un guasto che non c'e'.
2469
+ */
2470
+ interface DpeExpressionFormSupport {
2471
+ readonly isSupported: boolean;
2472
+ /** Presente **solo** quando la forma non e' supportata. E' il testo che il campo mostra. */
2473
+ readonly reason?: string;
2474
+ }
2475
+ /**
2476
+ * Decide se il campo formula si disabilita, e con quale motivo.
2477
+ *
2478
+ * Le tre regole, in quest'ordine e non intercambiabili:
2479
+ *
2480
+ * 1. **forma richiesta assente** -> supportato: il nodo non ospita formule, o la prima validazione
2481
+ * non e' ancora arrivata. Non c'e' niente da incrociare;
2482
+ * 2. **forme supportate non dichiarate** (`undefined` o `null`) -> supportato. E' la politica del
2483
+ * contratto: assente significa **non si disabilita niente**. Un ospite che non dichiara le
2484
+ * capacita' del proprio compilatore non autorizza l'editor a indovinarle, e un campo spento per
2485
+ * ignoranza toglie all'utente l'unica cosa che avrebbe: provare e leggere la risposta del
2486
+ * backend;
2487
+ * 3. **dichiarate e la forma non c'e'** -> non supportato. Un elenco **vuoto** entra qui, e ci
2488
+ * entra di proposito: vuoto non e' assente, e' un compilatore che dichiara di non compilare
2489
+ * nessuna forma.
2490
+ *
2491
+ * Nessuna di queste e' una regola di dominio: la forma la dice il backend, le capacita' pure.
2492
+ * Questa funzione fa solo l'intersezione e sceglie le parole italiane.
2493
+ */
2494
+ declare function dpeExpressionFormSupport(requiredForm: DpeExpressionForm | null | undefined, supportedForms: readonly DpeExpressionForm[] | null | undefined): DpeExpressionFormSupport;
2495
+ /** Quante voci porta un catalogo. Zero e' l'esito «il compilatore non si descrive», non un guasto. */
2496
+ declare function dpeFormulaCatalogSize(catalog: DpeFormulaCatalog): number;
2497
+
2498
+ /**
2499
+ * Il catalogo del linguaggio di formule, **conservato per nodo** — `frontend.md` §5-quater,
2500
+ * normativo.
2501
+ *
2502
+ * `getFormulaCatalog` non e' una chiamata leggera: lato libreria costa una passata completa di
2503
+ * grafo e di propagazione, e interroga il provider di metadati per **tutti** i datasource della
2504
+ * definizione, non solo per il cono a monte del nodo. Chiederlo a ogni apertura di un campo formula
2505
+ * e' il modo naturale di scriverlo e quello sbagliato, e non lascia traccia: non fallisce, si
2506
+ * limita a far pagare al backend N volte una risposta che non e' cambiata.
2507
+ *
2508
+ * Quindi: **una volta per nodo**, conservato, e invalidato quando cambia cio' che puo' cambiarne il
2509
+ * contenuto.
2510
+ *
2511
+ * Cosa questo store **non** fa, e non e' una dimenticanza:
2512
+ *
2513
+ * - **non valida niente.** Il catalogo dice cosa esiste, non se cio' che l'utente ha scritto va
2514
+ * bene. La grammatica e' del compilatore dell'ospite, il frontend non la conosce e non puo'
2515
+ * conoscerla: nessuna validazione di formula viene scritta in TypeScript, per nessun motivo
2516
+ * (ADR 0031/0036, `contracts.md` §7);
2517
+ * - **non decide il nome del linguaggio.** Quello e' `DpeEnvironment.expressionLanguage`, e arriva
2518
+ * anche quando il catalogo non arriva — che e' il caso piu' importante dei due, perche' un
2519
+ * dialetto fuori da `SupportedDialects` rende il catalogo nullo (ADR 0031 §5) proprio mentre
2520
+ * l'utente ha ancora bisogno di sapere in che lingua sta scrivendo;
2521
+ * - **non chiama se non deve.** Servono due cose: la primitiva **sovrascritta e non dichiarata non
2522
+ * servita** (`dpe-capabilities.ts`) e il compilatore che dichiara di descrivere il proprio
2523
+ * linguaggio (`providesFormulaCatalog`). Un compilatore laconico risponde un catalogo vuoto, che
2524
+ * e' legittimo (ADR 0036 §5): farsi pagare una passata di grafo per riceverlo e' spreco puro.
2525
+ *
2526
+ * Provider del **componente radice** come gli altri store: due editor sulla stessa pagina hanno due
2527
+ * documenti, quindi due cache.
2528
+ */
2529
+
2530
+ /**
2531
+ * L'impronta di cio' che puo' cambiare una risposta di `getFormulaCatalog`: **il nome del
2532
+ * documento** e **gli schemi che il backend ha propagato**.
2533
+ *
2534
+ * Le due parti corrispondono a cio' che la risposta contiene, e nessuna e' un indovinello: i
2535
+ * simboli `Column` *sono* le colonne che quel nodo vede, e quali siano lo decide la propagazione
2536
+ * dello schema, che e' del backend (**I4**). Qualunque altra impronta — «e' cambiata la topologia»,
2537
+ * «e' cambiato un alias di sorgente» — richiederebbe di sapere *quali* modifiche cambiano uno
2538
+ * schema, cioe' di riscrivere I4 in TypeScript.
2539
+ *
2540
+ * Conseguenza voluta, ed e' la ragione per cui questa funzione e' pura e verificabile: scrivere
2541
+ * nel testo di una formula **non** cambia l'impronta, quindi non invalida nulla. Rinominare un
2542
+ * alias a monte la cambia, e il catalogo si rilegge alla prossima apertura del nodo.
2543
+ *
2544
+ * Il nome del documento entra perche' prima della prima validazione gli schemi sono vuoti: senza
2545
+ * di esso due documenti diversi appena aperti avrebbero la stessa impronta, e il secondo
2546
+ * erediterebbe il catalogo del primo.
2547
+ *
2548
+ * **Qui c'era una terza parte, la forma dei nodi, e non c'e' piu'.** Era entrata quando la risposta
2549
+ * portava `requiredForm`, che dipende dal tipo del nodo mentre lo schema in uscita no: cambiare una
2550
+ * trasformazione da `Expression` a `ComputeRelative` lasciava l'impronta identica e la pastiglia
2551
+ * diceva la forma vecchia. Ora la forma arriva con la validazione e non con questa risposta, e
2552
+ * l'ingresso non esiste piu': misurato sui due lati, il contratto — il compilatore riceve
2553
+ * `DpeExpressionCatalogRequest`, cioe' **dialetto, colonne a monte e parametri**, e non il tipo del
2554
+ * nodo — e il browser, dove lo stesso nodo prima e dopo il cambio di tipo riceve un catalogo
2555
+ * identico (le stesse 32 voci). Toglierla non e' una semplificazione: e' non pagare una richiesta
2556
+ * per una risposta che non puo' essere cambiata.
2557
+ *
2558
+ * **Due ingressi restano scoperti, e sono scoperti da sempre:** il `dialect` e i `parameters` della
2559
+ * definizione, che pure entrano nella richiesta al compilatore. Oggi nessuno dei due si puo'
2560
+ * modificare a documento aperto — l'editor non li scrive, e caricarne un altro azzera gli schemi,
2561
+ * quindi l'impronta si muove lo stesso. Il giorno in cui compare un editor dei parametri, il posto
2562
+ * da cui ripartire e' questo.
2563
+ */
2564
+ declare function dpeFormulaCatalogSignature(definitionName: string, schemas: readonly DpeNodeSchemaInfo[]): string;
2565
+ declare class DpeFormulaCatalogStore {
2566
+ private readonly api;
2567
+ private readonly document;
2568
+ /**
2569
+ * La dichiarazione dell'ambiente si chiede **una volta all'apertura**, e chi la chiede e'
2570
+ * `DpeValidationService`. Rileggerla da qui sarebbe un secondo `getEnvironment` per la stessa
2571
+ * risposta — e per giunta due risposte che possono arrivare in ordine diverso.
2572
+ */
2573
+ private readonly validation;
2574
+ private readonly capabilities;
2575
+ private readonly _byNode;
2576
+ private readonly _pending;
2577
+ /**
2578
+ * Il nodo di cui si vuole il catalogo — **uno**, quello aperto.
2579
+ *
2580
+ * Esiste per un difetto trovato nel browser e non da nessun test: la disponibilita' dipende da
2581
+ * `getEnvironment`, che e' una chiamata di rete, e chi apre un nodo subito dopo aver aperto
2582
+ * l'editor chiede il catalogo **prima** che l'ambiente abbia risposto. La richiesta cadeva nel
2583
+ * vuoto e non veniva piu' ripetuta, perche' l'apertura del nodo era l'unico innesco: il campo
2584
+ * restava senza catalogo per sempre, senza errori, e riaprire lo stesso nodo non cambiava
2585
+ * niente. Tenere qui **l'intenzione** invece di agire subito la rende ripetibile quando la
2586
+ * condizione che mancava si verifica.
2587
+ */
2588
+ private readonly _wanted;
2589
+ /**
2590
+ * Il catalogo si puo' chiedere: primitiva disponibile **e** compilatore che dichiara di
2591
+ * descrivere il proprio linguaggio. Le due meta' restano separate perche' sono due fatti
2592
+ * diversi — il trasporto e il compilatore — e un solo booleano non permetterebbe di capire
2593
+ * quale dei due manca.
2594
+ */
2595
+ readonly isAvailable: Signal<boolean>;
2596
+ /**
2597
+ * L'impronta corrente: cambia quando cambia cio' che puo' cambiare una risposta, cioe' gli
2598
+ * **schemi** che il backend ha propagato — sono loro a decidere i simboli.
2599
+ *
2600
+ * Legge il documento, e va bene: il valore prodotto e' una stringa, e a parita' di stringa un
2601
+ * `computed` non notifica nessuno. Scrivere in una formula ricalcola l'impronta e non muove
2602
+ * niente — cioe' nessuna richiesta a ogni battitura, che resta la regola di `frontend.md`
2603
+ * §5-quater.
2604
+ */
2605
+ readonly signature: Signal<string>;
2606
+ /**
2607
+ * La prima validazione e' tornata, cioe' **gli schemi si conoscono**.
2608
+ *
2609
+ * Prima di allora il catalogo non si chiede, e non e' prudenza: i simboli `Column` sono le colonne
2610
+ * che il nodo vede, e chiederli quando gli schemi non sono ancora arrivati significa ricevere una
2611
+ * risposta che l'istante dopo e' scaduta — cioe' **due** chiamate per la stessa apertura, dove
2612
+ * ogni chiamata costa al backend una passata completa di grafo e di metadati. Misurato: aprire un
2613
+ * nodo subito dopo l'editor faceva salire il contatore di due.
2614
+ */
2615
+ private readonly hasValidated;
2616
+ /**
2617
+ * L'**involucro** noto per un nodo, se e' stato ottenuto con l'impronta corrente.
2618
+ *
2619
+ * Legge i signal, quindi si usa dentro un `computed` e resta reattivo — lo stesso schema di
2620
+ * `DpeMetadataStore.stateOf`.
2621
+ *
2622
+ * **Scade con l'impronta**: un catalogo ottenuto quando gli schemi erano altri non si restituisce
2623
+ * come se fosse attuale — dichiarerebbe disponibili simboli che non esistono piu'. Finche' il nodo
2624
+ * resta quello aperto, l'effect del costruttore ne chiede subito uno nuovo, quindi la scadenza si
2625
+ * vede al piu' come una sparizione momentanea del conteggio, non come un campo che resta muto.
2626
+ *
2627
+ * Scade anche l'esito d'errore, ed e' giusto: un `DPE_CATALOG_UNAVAILABLE` nasce da uno schema
2628
+ * che non si risolve, e cambiare gli schemi e' esattamente cio' che puo' averlo risolto.
2629
+ */
2630
+ resultOf(nodeName: string): DpeFormulaCatalogResult | undefined;
2631
+ /**
2632
+ * Il catalogo consegnato, **quando e' stato prodotto**. Puo' legittimamente essere vuoto: chi
2633
+ * rende non deve confondere «vuoto» con «assente», e per questo la decisione di cosa mostrare
2634
+ * passa da `outcomeOf` e non da qui.
2635
+ */
2636
+ catalogOf(nodeName: string): DpeFormulaCatalog | undefined;
2637
+ /**
2638
+ * Quale dei tre esiti del contratto si sta guardando — piu' «non lo so ancora».
2639
+ *
2640
+ * E' cio' che i componenti consumano: la tricotomia si legge **una volta**, in una funzione
2641
+ * pura, e non si riscrive in ogni ispettore con un `if` leggermente diverso.
2642
+ */
2643
+ outcomeOf(nodeName: string): DpeFormulaCatalogOutcome;
2644
+ /** Una richiesta per questo nodo e' in volo: lo stato di attesa si mostra sempre. */
2645
+ isLoading(nodeName: string): boolean;
2646
+ constructor();
2647
+ /**
2648
+ * Chiede il catalogo per un nodo, **se serve**. Idempotente: chiamarla a ogni apertura della
2649
+ * finestra non produce chiamate, chiamarla in un ciclo nemmeno.
2650
+ *
2651
+ * Fa **due** cose, e servono entrambe:
2652
+ *
2653
+ * 1. prova subito, sotto `untracked`, cosi' l'esito e' immediato quando le condizioni ci sono
2654
+ * gia'. Affidarsi al solo `_wanted` non basterebbe: riaperto lo **stesso** nodo il signal non
2655
+ * cambia valore e l'effect non riparte;
2656
+ * 2. registra l'intenzione in `_wanted`, cosi' quando cambia una delle condizioni che mancavano
2657
+ * — la disponibilita' dell'ambiente, l'impronta degli schemi — la richiesta viene onorata
2658
+ * senza che l'utente debba riaprire il nodo.
2659
+ *
2660
+ * **Ogni lettura di signal e' in `untracked`**, e non e' prudenza: i chiamanti sono `effect` degli
2661
+ * ispettori, e un `this.document.definition()` letto qui diventerebbe una dipendenza di
2662
+ * quell'effect — cioe' una richiesta di catalogo **a ogni battitura**, che e' il difetto che
2663
+ * questo store esiste per evitare. Il sintomo non sarebbe un errore: sarebbe un backend che
2664
+ * macina grafi mentre qualcuno scrive.
2665
+ */
2666
+ requestFor(nodeName: string): void;
2667
+ /**
2668
+ * La chiamata, **se serve davvero**: non c'e' gia' una richiesta in volo per quel nodo, e cio'
2669
+ * che e' in cache non e' stato ottenuto con l'impronta corrente.
2670
+ *
2671
+ * Tutte le letture stanno sotto `untracked` da parte dei chiamanti: sono signal, e legarli
2672
+ * all'effect vorrebbe dire rileggere il catalogo a ogni modifica del documento.
2673
+ */
2674
+ private fetchIfNeeded;
2675
+ /**
2676
+ * Rilettura forzata, per chi vuole il catalogo aggiornato senza aspettare un cambio di impronta.
2677
+ * Non ha un consumatore nell'editor di oggi ed esiste perche' una cache senza modo di essere
2678
+ * invalidata a mano e' una cache che prima o poi si aggira con un ricaricamento della pagina.
2679
+ */
2680
+ refresh(nodeName: string): void;
2681
+ private fetch;
2682
+ private put;
2683
+ private setPending;
2684
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeFormulaCatalogStore, never>;
2685
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<DpeFormulaCatalogStore>;
2686
+ }
2687
+
1698
2688
  interface DpeLayoutNodeInput {
1699
2689
  name: string;
1700
2690
  width: number;
@@ -1749,7 +2739,7 @@ declare class DpeMetadataStore {
1749
2739
  readonly isLoadingTables: _angular_core.Signal<boolean>;
1750
2740
  /** Idempotente: la prima chiamata carica, le successive non fanno nulla. */
1751
2741
  loadTables(): void;
1752
- /** Stato noto di una tabella, se già richiesta. */
2742
+ /** Stato noto di una tabella, se gia' richiesta. */
1753
2743
  stateOf(tableName: string): DpeTableState | undefined;
1754
2744
  /** Chiede la descrizione di una tabella una sola volta per nome. */
1755
2745
  describe(tableName: string): void;
@@ -1793,6 +2783,12 @@ interface DpeNodeCategory {
1793
2783
  */
1794
2784
  isNotCompilableInV1: boolean;
1795
2785
  }
2786
+ /**
2787
+ * Le categorie nell'ordine di `DPE_NODE_COLLECTIONS`, che e' l'ordine della palette. **Derivate,
2788
+ * non riscritte**: l'ordine vive in un posto solo — il modello, dove un controllo di tipo lo tiene
2789
+ * totale e senza ripetizioni — e la collezione di ogni categoria e' la stessa variabile con cui se
2790
+ * ne legge la voce, quindi chiave e campo non hanno modo di divergere.
2791
+ */
1796
2792
  declare const DPE_NODE_CATEGORIES: readonly DpeNodeCategory[];
1797
2793
  declare function dpeNodeCategory(collection: DpeNodeCollectionName): DpeNodeCategory;
1798
2794
  /** Nomi dei dialetti per il selettore. La libreria conosce **solo** il nome (ADR 0009). */
@@ -1843,7 +2839,7 @@ declare function dpeNodeIconPaths(collection: DpeNodeCollectionName): readonly s
1843
2839
  * Tutto il resto lo compila l'utente nell'ispettore, e cosa sia obbligatorio lo dice il
1844
2840
  * backend.
1845
2841
  *
1846
- * Il nome candidato e' unico rispetto ai nomi già presenti con confronto **esatto**
2842
+ * Il nome candidato e' unico rispetto ai nomi gia' presenti con confronto **esatto**
1847
2843
  * (`contracts.md` §2: unicita' verificata `OrdinalIgnoreCase`, risoluzione `Ordinal`). Qui il
1848
2844
  * confronto e' insensibile al caso di proposito: proporre `Filtro2` accanto a un `filtro2`
1849
2845
  * esistente creerebbe un `DPE_MODEL_NAME_DUPLICATE` a nome dell'editor, non dell'utente.
@@ -1893,6 +2889,30 @@ declare class DpeValidationService {
1893
2889
  * questo che i due si tengono separati: il confronto e' l'unica cosa che l'editor puo' dire.
1894
2890
  */
1895
2891
  private readonly _environmentDialect;
2892
+ /**
2893
+ * Il nome del **linguaggio di formule** dichiarato dall'ambiente (ADR 0031/0036). Serve
2894
+ * all'etichetta del campo espressione, e arriva da qui e non dal catalogo per una ragione
2895
+ * precisa: il catalogo puo' essere assente o nullo — compilatore che non descrive il proprio
2896
+ * linguaggio, dialetto non coperto — mentre il nome del linguaggio si sa sempre. Letto dal
2897
+ * catalogo, l'editor resterebbe muto proprio nei casi in cui serve.
2898
+ */
2899
+ private readonly _expressionLanguage;
2900
+ /** Il compilatore descrive il proprio linguaggio: se no, `getFormulaCatalog` non si chiama. */
2901
+ private readonly _providesFormulaCatalog;
2902
+ /**
2903
+ * Le forme che il compilatore registrato sa produrre (ADR 0031), dall'ambiente. E' il **secondo
2904
+ * operando** dell'incrocio che disabilita un campo formula incompilabile; il primo,
2905
+ * `requiredForm`, e' per nodo e arriva con la **validazione**, su `DpeNodeSchemaInfo`.
2906
+ *
2907
+ * I due arrivano da due chiamate diverse, ed e' la ragione per cui questo campo sta qui: le forme
2908
+ * supportate sono dell'**installazione** e si chiedono una volta all'apertura, la forma richiesta
2909
+ * e' del **nodo** e si aggiorna a ogni validazione.
2910
+ *
2911
+ * `undefined` non e' «nessuna forma», e' «non dichiarate», e non disabilita niente: la
2912
+ * distinzione e' tutta la politica del contratto e per questo non si normalizza qui in un
2913
+ * elenco vuoto, che direbbe l'opposto.
2914
+ */
2915
+ private readonly _supportedForms;
1896
2916
  readonly isValidating: _angular_core.Signal<boolean>;
1897
2917
  readonly isCompiling: _angular_core.Signal<boolean>;
1898
2918
  readonly error: _angular_core.Signal<DpeApiError | undefined>;
@@ -1902,6 +2922,9 @@ declare class DpeValidationService {
1902
2922
  readonly justSaved: _angular_core.Signal<boolean>;
1903
2923
  readonly saveError: _angular_core.Signal<DpeApiError | undefined>;
1904
2924
  readonly environmentDialect: _angular_core.Signal<SqlDialectKind | undefined>;
2925
+ readonly expressionLanguage: _angular_core.Signal<string | undefined>;
2926
+ readonly providesFormulaCatalog: _angular_core.Signal<boolean>;
2927
+ readonly supportedForms: _angular_core.Signal<readonly DpeExpressionForm[] | undefined>;
1905
2928
  /** Vero finche' non e' arrivata la prima risposta: la UI non deve dire "nessun problema". */
1906
2929
  readonly hasResult: _angular_core.Signal<boolean>;
1907
2930
  constructor();
@@ -1983,8 +3006,9 @@ declare class DpeBuilderComponent {
1983
3006
  protected readonly dialect: Signal<SqlDialectKind>;
1984
3007
  /**
1985
3008
  * Disallineamento fra cio' che l'ambiente dichiara e cio' che la definizione porta. Si
1986
- * **segnala** e non si corregge: correggere vorrebbe dire migrare le espressioni SQL native
1987
- * (ADR 0006), che e' dell'host. Assente `getEnvironment`, non c'e' niente da confrontare.
3009
+ * **segnala** e non si corregge: correggere vorrebbe dire cambiare le capacita' con cui la
3010
+ * definizione verra' compilata, che e' dell'host. Assente `getEnvironment`, non c'e' niente da
3011
+ * confrontare.
1988
3012
  */
1989
3013
  protected readonly dialectMismatch: Signal<SqlDialectKind | undefined>;
1990
3014
  /**
@@ -2138,7 +3162,18 @@ interface DpeCanvasNode {
2138
3162
  * colore proprio. Sono due situazioni diverse e l'utente deve capire subito quale guarda.
2139
3163
  */
2140
3164
  isNotCompilable: boolean;
2141
- /** Numero di colonne dello schema di uscita, quando il backend lo ha detto. */
3165
+ /**
3166
+ * Numero di colonne dello schema di uscita. `null` significa **nessuna pastiglia**, e ci sono
3167
+ * due modi di arrivarci:
3168
+ *
3169
+ * - il backend non ha dichiarato di aver derivato lo schema (`hasSchema`, ADR 0041): un «0 col.»
3170
+ * sarebbe un'affermazione che nessuno ha fatto;
3171
+ * - il nodo e' un **pozzo**: il conteggio risponde a «cosa esce di qui», e da un pozzo non esce
3172
+ * niente. Lo zero e' vero — e' la condizione normale di ogni writeback — ed e' la risposta a
3173
+ * una domanda che non si pone.
3174
+ *
3175
+ * Sui nodi **non** pozzo lo zero si mostra: li' significa `DPE_SCHEMA_EMPTY`, che e' un errore.
3176
+ */
2142
3177
  columnCount: number | null;
2143
3178
  }
2144
3179
  interface DpeCanvasEdge {
@@ -2227,7 +3262,7 @@ declare class DpeCanvasComponent {
2227
3262
  sourceId: string;
2228
3263
  targetId?: string;
2229
3264
  }): void;
2230
- /** Riassegnazione di un arco già disegnato, da un capo o dall'altro. */
3265
+ /** Riassegnazione di un arco gia' disegnato, da un capo o dall'altro. */
2231
3266
  onReassignConnection(event: {
2232
3267
  endpoint: string;
2233
3268
  previousSourceId: string;
@@ -2260,9 +3295,13 @@ declare class DpeCanvasComponent {
2260
3295
  nodeIds: string[];
2261
3296
  }): void;
2262
3297
  /**
2263
- * Rilascio di una voce trascinata dalla palette. `externalItemRect` e' già nel sistema di
3298
+ * Rilascio di una voce trascinata dalla palette. `externalItemRect` e' gia' nel sistema di
2264
3299
  * coordinate del canvas: convertirlo a mano dal viewport sarebbe rifare la trasformazione
2265
3300
  * di zoom e panoramica della libreria.
3301
+ *
3302
+ * `data` e' `unknown` per @foblex/flow, e qui il dato si **controlla** invece di convertirlo con
3303
+ * un `as`: un rilascio che non porta una collezione di nodi si ignora, come si ignorava un dato
3304
+ * vuoto. E' il confine che permette a `dpeNodeCategory` di lanciare fuori dall'unione.
2266
3305
  */
2267
3306
  onCreateNode(event: {
2268
3307
  data: unknown;
@@ -2464,7 +3503,33 @@ declare class DpeNodeFactsComponent {
2464
3503
  */
2465
3504
  readonly isNotCompilable: _angular_core.Signal<boolean>;
2466
3505
  readonly columns: _angular_core.Signal<_esfaenza_dpe_builder.DpeColumnInfo[]>;
2467
- readonly diagnostics: _angular_core.Signal<_esfaenza_dpe_builder.Diagnostic[]>;
3506
+ /**
3507
+ * Se `columns` e' un **fatto** (ADR 0041). E' l'unica cosa che `hasSchema` dice: non dice che il
3508
+ * nodo sta bene, non dice che ha colonne, non dice che e' compilabile.
3509
+ *
3510
+ * `=== true` e non un confronto lasco: assente significa `false`, perche' un ospite che non
3511
+ * serializza i booleani falsi non manda affatto la proprieta' — e il verso prudente e' «non lo
3512
+ * so», non «zero colonne».
3513
+ */
3514
+ readonly hasSchema: _angular_core.Signal<boolean>;
3515
+ /**
3516
+ * Il nodo e' un **pozzo**. Non si deduce da niente: si legge la collezione di appartenenza dal
3517
+ * documento e si chiede la categoria al catalogo dei nodi — la stessa che il view model del
3518
+ * canvas usa per decidere se disegnare la porta di uscita, e per la stessa domanda («da qui esce
3519
+ * qualcosa?»).
3520
+ *
3521
+ * Serve perche' uno schema di uscita **vuoto** significa due cose diverse su un pozzo e su un
3522
+ * nodo di mezzo, e la differenza non e' nei dati: e' nel tipo di nodo, che il backend ci ha gia'
3523
+ * detto qual e'.
3524
+ */
3525
+ readonly isSink: _angular_core.Signal<boolean>;
3526
+ readonly diagnostics: _angular_core.Signal<Diagnostic[]>;
3527
+ /**
3528
+ * Il campo in causa, dalla stessa funzione che gli ispettori usano per agganciare il rilievo al
3529
+ * controllo (`contracts.md` §1). Vuoto quando la diagnostica riguarda il nodo intero, e allora
3530
+ * la riga non mostra niente: e' un fatto sul nodo, non su un campo.
3531
+ */
3532
+ protected fieldOf(diagnostic: Diagnostic): string | undefined;
2468
3533
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeNodeFactsComponent, never>;
2469
3534
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeNodeFactsComponent, "dpe-node-facts", never, { "nodeName": { "alias": "nodeName"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
2470
3535
  }
@@ -2484,6 +3549,23 @@ declare abstract class DpeNodeInspectorBase<TNode extends DpeAnyNode = DpeAnyNod
2484
3549
  readonly isNotCompilable: _angular_core.Signal<boolean>;
2485
3550
  /** Colonne prodotte dal nodo, secondo il backend. Mai calcolate qui (**I4**). */
2486
3551
  readonly outputColumns: _angular_core.Signal<readonly DpeColumnInfo[]>;
3552
+ /**
3553
+ * La forma pretesa dai siti di espressione del nodo, **dal backend** (ADR 0031 §1).
3554
+ *
3555
+ * Si legge dallo **schema** e non dal catalogo delle formule, ed e' il punto della faccenda: la
3556
+ * forma e' cio' che la libreria ha derivato su questo nodo — come le colonne e la compilabilita'
3557
+ * qui sopra — mentre il catalogo e' cio' che il compilatore offre, e **arriva solo quando il
3558
+ * compilatore risponde**. Finche' viaggiava col catalogo, un ospite che dichiara di non
3559
+ * descrivere il proprio linguaggio non faceva chiamare la rotta e la forma non arrivava mai.
3560
+ *
3561
+ * Assente significa «questo nodo non ospita formule», ed e' uno stato normale: nessuna forma si
3562
+ * indovina dal tipo di nodo, che sarebbe una regola di dominio in TypeScript.
3563
+ *
3564
+ * Sta sulla base e non sui due ispettori che la usano perche' e' un campo dello stesso record da
3565
+ * cui gia' si leggono `outputColumns` e `isNotCompilable`: leggerlo due volte in due componenti
3566
+ * significherebbe due letture da tenere allineate.
3567
+ */
3568
+ readonly requiredForm: _angular_core.Signal<DpeExpressionForm | undefined>;
2487
3569
  /**
2488
3570
  * Colonne disponibili **in ingresso**: l'unione degli schemi dei nodi a monte, nell'ordine.
2489
3571
  * Arrivano dal backend; se la validazione non e' ancora tornata l'elenco e' vuoto e i campi
@@ -2492,11 +3574,46 @@ declare abstract class DpeNodeInspectorBase<TNode extends DpeAnyNode = DpeAnyNod
2492
3574
  readonly inputColumns: _angular_core.Signal<readonly DpeColumnInfo[]>;
2493
3575
  /** I parametri dichiarati sulla radice: servono a filtri e mapping dei writeback. */
2494
3576
  readonly parameters: _angular_core.Signal<_esfaenza_dpe_builder.DpeParameter[]>;
2495
- /** Le diagnostiche su un campo preciso, per mostrarle **accanto** al controllo. */
3577
+ /**
3578
+ * Le diagnostiche su un campo preciso, per mostrarle **accanto** al controllo.
3579
+ *
3580
+ * Il nome del campo si chiede a `dpeDiagnosticField` invece di leggere `path.field` qui:
3581
+ * `contracts.md` §1 nomina quella funzione come **il** punto in cui l'editor aggancia il rilievo
3582
+ * al controllo, e una funzione sola che sappia come una diagnostica nomina il proprio campo e'
3583
+ * la stessa ragione per cui esiste `DiagnosticArgumentKeys`. Il percorso e' gia' pubblicato in
3584
+ * tre forme diverse: il giorno in cui succede anche al campo, il posto da cambiare e' uno.
3585
+ */
2496
3586
  issuesOn(field: string): Diagnostic[];
2497
3587
  hasIssueOn(field: string): boolean;
3588
+ /**
3589
+ * Le diagnostiche su **una riga** di una collezione del nodo (`expressionFields[2].expression`).
3590
+ *
3591
+ * Esiste accanto a `issuesOn` perche' quella filtra per solo nome di campo, e in una collezione
3592
+ * il nome si ripete su ogni riga: l'errore della prima formula finirebbe sotto la terza.
3593
+ */
3594
+ issuesOnItem(collection: string, index: number, field: string): Diagnostic[];
3595
+ /**
3596
+ * «Il campo porta un valore», nel senso della regola di rendering di `frontend.md` §5-ter:
3597
+ * **un campo che porta un valore si rende anche fuori dalla propria condizione**.
3598
+ *
3599
+ * E' l'unica meta' della regola che serve anche **fuori** dalla tabella delle condizioni
3600
+ * (`core/dpe-conditional-fields.ts`): un campo dentro una riga di collezione non ha una voce
3601
+ * in tabella, perche' la ripulitura toglie chiavi del nodo, ma la sua resa segue la stessa
3602
+ * regola. Il predicato e' quello, non una seconda copia: qui si delega e basta.
3603
+ */
3604
+ protected declares(value: unknown): boolean;
2498
3605
  /** Applica una modifica al nodo. */
2499
3606
  protected patch(patch: Partial<TNode>): void;
3607
+ /**
3608
+ * Cambia un **discriminante** e toglie in un colpo solo i campi che con il valore nuovo non si
3609
+ * applicano piu', secondo la tabella delle condizioni del nodo.
3610
+ *
3611
+ * E' la seconda strada che legge quelle condizioni — la prima e' la resa di §5-ter — e legge la
3612
+ * **stessa** tabella: una riga aggiunta domani entra qui senza che nessuno la ricopi, che e' il
3613
+ * punto di `core/dpe-conditional-fields.ts`. La ripulitura resta una modifica come le altre e
3614
+ * rientra nell'annullamento globale, perche' passa da `patch`.
3615
+ */
3616
+ protected patchPruned<TConditions extends DpeConditionalFields<TNode>>(change: Partial<TNode>, conditions: TConditions): void;
2500
3617
  /**
2501
3618
  * Campo semplice: valore vuoto → chiave **rimossa**, non stringa vuota. Il backend
2502
3619
  * distingue assente da vuoto (`DPE_MODEL_REQUIRED_MISSING` contro un valore non valido), e
@@ -2504,6 +3621,20 @@ declare abstract class DpeNodeInspectorBase<TNode extends DpeAnyNode = DpeAnyNod
2504
3621
  * semantica invece di ripulire il campo.
2505
3622
  */
2506
3623
  protected setField(field: keyof TNode & string, value: unknown): void;
3624
+ /**
3625
+ * Interruttore il cui **default e' `false`**: spento → chiave **rimossa**, non `false` scritto.
3626
+ *
3627
+ * Due conseguenze, e la seconda e' quella che serve a §5-ter. La prima e' **I7**: chi accende e
3628
+ * rispegne per curiosita' non deve lasciare nel documento una chiave che non c'era. La seconda
3629
+ * e' che cosi' una casella **sa dire «assente»**: il controllo che rende un campo fuori dalla
3630
+ * propria condizione deve poterlo riportare all'assenza, e una casella che scrivesse `false`
3631
+ * resterebbe accesa-o-spenta senza mai togliere niente — resa e inerte, che e' il difetto
3632
+ * travestito da soluzione.
3633
+ *
3634
+ * **Non** si usa dove l'assenza vale `true` (`includesSelfValue`): li' `false` e' una
3635
+ * dichiarazione vera e toglierla direbbe il contrario.
3636
+ */
3637
+ protected setFlag(field: keyof TNode & string, value: boolean): void;
2507
3638
  /** Numero da un campo di testo: vuoto o non numerico → assente, non `0`. */
2508
3639
  protected toNumber(value: string): number | undefined;
2509
3640
  /** Lettura tipizzata di un valore da un evento di input, senza `any` nei template. */
@@ -2569,10 +3700,17 @@ declare class DpeSchemaPanelComponent {
2569
3700
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeSchemaPanelComponent, "dpe-schema-panel", never, {}, {}, never, never, true, never>;
2570
3701
  }
2571
3702
 
3703
+ /**
3704
+ * I tre soli fatti che un writeback compilato e un **piano di artefatto** (ADR 0029) hanno in
3705
+ * comune, e gli unici che questo pannello mostra. Tipizzare la sezione sul minimo condiviso
3706
+ * evita un'unione che il template dovrebbe poi discriminare per rendere le stesse tre cose: qui
3707
+ * cambia il tipo, non il comportamento.
3708
+ */
3709
+ type DpeSqlPreviewItem = Pick<DpeCompiledWriteback & DpeArtifactPlan, 'writebackName' | 'sequence' | 'statement'>;
2572
3710
  interface DpeSqlSection {
2573
3711
  title: string;
2574
3712
  hint: string;
2575
- writebacks: readonly DpeCompiledWriteback[];
3713
+ writebacks: readonly DpeSqlPreviewItem[];
2576
3714
  }
2577
3715
  declare class DpeSqlPreviewComponent {
2578
3716
  private readonly store;
@@ -2590,20 +3728,140 @@ declare class DpeExpressionEditorComponent {
2590
3728
  readonly label: _angular_core.InputSignal<string>;
2591
3729
  readonly value: _angular_core.InputSignal<string | undefined>;
2592
3730
  readonly placeholder: _angular_core.InputSignal<string>;
2593
- readonly dialect: _angular_core.InputSignal<SqlDialectKind>;
2594
3731
  /**
2595
- * I nomi delle colonne a monte, **come suggerimento** e non come elenco chiuso: sono cio'
2596
- * che il backend ha propagato, ma dentro l'espressione si puo' scrivere qualunque SQL.
3732
+ * Il nome del linguaggio di formule dichiarato dall'ambiente. Assente: l'etichetta non nomina
3733
+ * niente. **Non** ripiega sul dialetto — sarebbe la bugia che questo lotto e' venuto a togliere.
3734
+ */
3735
+ readonly language: _angular_core.InputSignal<string | undefined>;
3736
+ /**
3737
+ * I nomi delle colonne a monte, **come suggerimento**: sono cio' che il backend ha propagato
3738
+ * (**I4**), e l'editor non li calcola.
2597
3739
  */
2598
3740
  readonly columns: _angular_core.InputSignal<readonly string[]>;
3741
+ /**
3742
+ * Le diagnostiche del backend **su questo campo**, gia' filtrate da chi conosce il percorso.
3743
+ * Si rendono e basta: il messaggio lo compone il backend, che e' l'unico posto in cui un
3744
+ * messaggio viene composto.
3745
+ */
3746
+ readonly issues: _angular_core.InputSignal<readonly Diagnostic[]>;
3747
+ /**
3748
+ * **Quale dei tre esiti del catalogo** si sta guardando, gia' letto da `dpeFormulaCatalogOutcome`.
3749
+ *
3750
+ * Prende l'esito e non il catalogo perche' il catalogo da solo non basta piu' a distinguerli: un
3751
+ * compilatore che non descrive il proprio linguaggio consegna il catalogo **presente e vuoto**,
3752
+ * quindi «assente» e «vuoto» sono due situazioni diverse che un solo oggetto nullabile
3753
+ * appiattiva — ed e' l'appiattimento che faceva sembrare uguali un dialetto non coperto e un
3754
+ * backend rotto.
3755
+ */
3756
+ readonly outcome: _angular_core.InputSignal<DpeFormulaCatalogOutcome>;
3757
+ /**
3758
+ * La forma pretesa dal campo, **dal backend**. Assente: il campo non la nomina. Non si deduce
3759
+ * dal tipo di nodo, che sarebbe una regola di dominio scritta dalla parte sbagliata del confine.
3760
+ */
3761
+ readonly requiredForm: _angular_core.InputSignal<DpeExpressionForm | undefined>;
3762
+ /**
3763
+ * L'incrocio **gia' fatto** fra la forma richiesta da questo nodo e le forme che il compilatore
3764
+ * registrato sa produrre (`DpeEnvironment.supportedForms`), come per `outcome`: il componente
3765
+ * riceve l'esito, non i due operandi.
3766
+ *
3767
+ * Il difetto predefinito e' «supportato», ed e' la politica del contratto: **capacita' non
3768
+ * dichiarate non disabilitano niente**. Un ospite che monta questo componente senza passare
3769
+ * nulla ottiene un campo che si scrive, non uno spento per ignoranza.
3770
+ */
3771
+ readonly formSupport: _angular_core.InputSignal<DpeExpressionFormSupport>;
3772
+ /**
3773
+ * **Una validazione e' in volo**, quindi la forma qui sopra puo' non essere ancora quella del
3774
+ * documento che l'utente ha davanti (ADR 0042). La pastiglia si segna «in aggiornamento» e
3775
+ * smette di asserire; il **blocco resta applicato**.
3776
+ *
3777
+ * E' di **documento** e **transitorio**, e per questo non e' una regola di dominio: arriva da
3778
+ * `DpeValidationService.isValidating`, che esisteva gia'. L'editor non sa — e non deve sapere —
3779
+ * che la forma dipende dal tipo del nodo: saperlo sarebbe riscrivere in TypeScript la regola che
3780
+ * `requiredForm` attraversa il confine per non avere.
3781
+ *
3782
+ * Non e' «il documento e' cambiato dall'ultima validazione», che e' il rimedio che l'ADR 0042
3783
+ * rifiuta: quello sarebbe vero **per tutta** la digitazione e spegnerebbe la pastiglia proprio
3784
+ * mentre si scrive nel campo che accompagna. `isValidating` diventa vero solo dopo la pausa di
3785
+ * digitazione, quindi mentre si scrive questa pastiglia resta ferma — e corretta, perche' la
3786
+ * forma non e' cambiata.
3787
+ *
3788
+ * Difetto predefinito `false`: un ospite che monta il componente senza passare nulla ottiene una
3789
+ * pastiglia asserita, che e' cio' che era prima.
3790
+ */
3791
+ readonly isFormUpdating: _angular_core.InputSignal<boolean>;
3792
+ readonly isCatalogLoading: _angular_core.InputSignal<boolean>;
2599
3793
  readonly controlId: _angular_core.InputSignal<string>;
2600
3794
  readonly valueChange: _angular_core.OutputEmitterRef<string>;
2601
- readonly dialectLabel: _angular_core.Signal<string>;
3795
+ readonly hasError: _angular_core.Signal<boolean>;
2602
3796
  /** Elenco troncato: dieci nomi sono un aiuto, cinquanta sono un muro di testo. */
2603
3797
  readonly columnHint: _angular_core.Signal<string>;
3798
+ /**
3799
+ * La forma pretesa, detta all'utente. Assente quando il nodo non ospita formule: il campo non
3800
+ * nomina nessuna forma di ripiego, che sarebbe la deduzione vietata travestita da default.
3801
+ */
3802
+ readonly formPrompt: _angular_core.Signal<string | undefined>;
3803
+ /**
3804
+ * La classe della pastiglia. Binding a stringa e nessuna classe statica accanto, come per il
3805
+ * controllo bloccato: il binding governa l'intera lista.
3806
+ *
3807
+ * Il modificatore non cambia il testo, cambia il **tono**: la pastiglia perde la tinta d'accento
3808
+ * — che e' cio' che la faceva leggere come un fatto corrente — e prende il bordo tratteggiato
3809
+ * della cosa provvisoria.
3810
+ */
3811
+ readonly formClass: _angular_core.Signal<"dpe-expr__form dpe-expr__form--updating" | "dpe-expr__form">;
3812
+ /**
3813
+ * Il titolo dice **cosa aspettarsi**, e nella finestra di aggiornamento dice anche che il blocco
3814
+ * non si tocca: e' la meta' che l'utente non puo' dedurre dal colore, e senza la quale un campo
3815
+ * che non accetta testo accanto a un'etichetta incerta sembra rotto.
3816
+ */
3817
+ readonly formTitle: _angular_core.Signal<string>;
3818
+ /** `aria-busy` invece del solo colore: chi usa un lettore di schermo deve sentirlo. */
3819
+ readonly ariaBusy: _angular_core.Signal<"true" | null>;
3820
+ /** Il campo non si scrive: la forma richiesta qui non e' fra quelle che il compilatore produce. */
3821
+ readonly isBlocked: _angular_core.Signal<boolean>;
3822
+ /**
3823
+ * Il motivo, **presente solo quando il campo e' bloccato**. Un campo inerte e muto fa cercare
3824
+ * all'utente un errore nella propria formula, che e' l'unico posto in cui il problema non sta.
3825
+ */
3826
+ readonly blockedReason: _angular_core.Signal<string | undefined>;
3827
+ /**
3828
+ * La classe del controllo bloccato. Binding a stringa e nessuna classe statica accanto, come per
3829
+ * i rilievi: il binding governa l'intera lista e una classe scritta anche nell'attributo statico
3830
+ * sembra ridondante finche' non sparisce.
3831
+ */
3832
+ readonly inputClass: _angular_core.Signal<"" | "dpe-expr__input--blocked">;
3833
+ /** L'esito di fallimento, quando e' quello: il template rende solo se c'e'. */
3834
+ readonly failure: _angular_core.Signal<{
3835
+ readonly kind: "Failed";
3836
+ readonly lead: Diagnostic;
3837
+ readonly details: readonly Diagnostic[];
3838
+ readonly hasError: boolean;
3839
+ } | undefined>;
3840
+ /**
3841
+ * Il blocco del fallimento prende il bordo dell'errore quando fra le diagnostiche c'e' un
3842
+ * `Error`, quello dell'avviso altrimenti. Non e' decorazione: «il catalogo non c'e' perche' la
3843
+ * definizione e' rotta a monte» e «il catalogo non c'e' e basta» si correggono in modi diversi.
3844
+ */
3845
+ readonly failureClass: _angular_core.Signal<"dpe-note dpe-note--danger" | "dpe-note dpe-note--warning">;
3846
+ /**
3847
+ * Cosa il linguaggio offre **qui**, in numeri. E' deliberatamente un conteggio: dice che il
3848
+ * catalogo e' arrivato e che dipende dal nodo (i simboli cambiano con lo schema a monte), senza
3849
+ * anticipare l'elenco navigabile, che e' un componente e va progettato guardandolo.
3850
+ *
3851
+ * Solo per l'esito `Palette`: un conteggio di zeri sotto un campo direbbe che qualcosa e'
3852
+ * andato storto, mentre il compilatore ha soltanto scelto di non descriversi.
3853
+ */
3854
+ readonly catalogHint: _angular_core.Signal<string | undefined>;
3855
+ /**
3856
+ * `aria-describedby` porta **il suggerimento, i rilievi e il motivo per cui la tavolozza manca**:
3857
+ * un lettore di schermo deve sentire l'errore del compilatore leggendo il campo, non cercandolo
3858
+ * piu' in basso, e deve sapere che qui non c'e' aiuto disponibile prima di scrivere.
3859
+ */
3860
+ readonly describedBy: _angular_core.Signal<string>;
3861
+ protected issueClass(issue: Diagnostic): string;
2604
3862
  protected text(event: Event): string;
2605
3863
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeExpressionEditorComponent, never>;
2606
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeExpressionEditorComponent, "dpe-expression-editor", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "dialect": { "alias": "dialect"; "required": true; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
3864
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeExpressionEditorComponent, "dpe-expression-editor", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "language": { "alias": "language"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "issues": { "alias": "issues"; "required": false; "isSignal": true; }; "outcome": { "alias": "outcome"; "required": false; "isSignal": true; }; "requiredForm": { "alias": "requiredForm"; "required": false; "isSignal": true; }; "formSupport": { "alias": "formSupport"; "required": false; "isSignal": true; }; "isFormUpdating": { "alias": "isFormUpdating"; "required": false; "isSignal": true; }; "isCatalogLoading": { "alias": "isCatalogLoading"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
2607
3865
  }
2608
3866
 
2609
3867
  declare class DpeColumnTypeEditorComponent {
@@ -2613,6 +3871,9 @@ declare class DpeColumnTypeEditorComponent {
2613
3871
  protected readonly types: readonly LogicalType[];
2614
3872
  readonly kind: _angular_core.Signal<LogicalType>;
2615
3873
  readonly allowedValues: _angular_core.Signal<string>;
3874
+ readonly showsLength: _angular_core.Signal<boolean>;
3875
+ readonly showsPrecision: _angular_core.Signal<boolean>;
3876
+ readonly showsAllowedValues: _angular_core.Signal<boolean>;
2616
3877
  protected onKind(kind: string): void;
2617
3878
  protected onNumber(field: 'length' | 'precision' | 'scale', raw: string): void;
2618
3879
  protected onAllowedValues(raw: string): void;
@@ -2636,5 +3897,5 @@ declare class DpeNodeIconComponent {
2636
3897
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeNodeIconComponent, "dpe-node-icon", never, { "collection": { "alias": "collection"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
2637
3898
  }
2638
3899
 
2639
- export { DPE_API_ERROR_FALLBACK_MESSAGE, DPE_BUILDER_HTTP_CONFIG, DPE_DIALECT_LABELS, DPE_LAYOUT_KEY, DPE_NODE_CATEGORIES, DPE_NODE_COLLECTIONS, DPE_NODE_HEIGHT, DPE_NODE_ICON_PATHS, DPE_NODE_NOT_COMPILABLE, DPE_SOURCE_SLOTS, DpeApiError, DpeBuilderApi, DpeBuilderComponent, DpeCanvasComponent, DpeCatalogComponent, DpeCatalogStore, DpeColumnTypeEditorComponent, DpeDiagnosticsPanelComponent, DpeDocumentStore, DpeExpressionEditorComponent, DpeLayoutService, DpeMetadataStore, DpeNodeDialogComponent, DpeNodeFactsComponent, DpeNodeIconComponent, DpeNodeInspectorBase, DpeNodeInspectorComponent, DpeNodePaletteComponent, DpeSchemaPanelComponent, DpeSelectValueDirective, DpeSqlPreviewComponent, DpeValidationService, HttpDpeBuilderApi, diagnosticPathToString, dpeAllNodes, dpeBuildGraph, dpeCountReferences, dpeCreateCommandAvailability, dpeCreateNode, dpeDefinitionLevelDiagnostics, dpeDiagnosticField, dpeDiagnosticLocationLabel, dpeDiagnosticNodeName, dpeEdgeId, dpeEmptyDefinition, dpeFindNode, dpeGroupDiagnosticsByNode, dpeHasCompleteLayout, dpeInputPortId, dpeInputPorts, dpeIsDialectDiagnostic, dpeIsNotCompilable, dpeIsPrimitiveAvailable, dpeIsRectFullyVisible, dpeKnownNodeNames, dpeNodeCategory, dpeNodeIconFamily, dpeNodeIconFamilyClass, dpeNodeIconPaths, dpeNodeId, dpeNodeSourceReferences, dpeNodeSubtitle, dpeNodeWidth, dpeNodeWidthClass, dpeOutputPortId, dpeParseInputPortId, dpeParseNodeId, dpeParseOutputPortId, dpeProposeNodeName, dpeProposeWritebackSequence, dpeReadCapabilities, dpeReadNodePosition, dpeRenameNode, dpeWorstSeverity, dpeWriteNodePosition, dpeWriteSourceReference, provideDpeBuilderHttpApi };
2640
- export type { AggregateField, AggregateFunction, AggregateNode, AppendNode, AtomicWritebackNode, AtomicWritebackRelationship, ColumnType, CsvArtifactOptions, CsvDelimiter, CsvSourceOptions, CustomNode, CustomNodeParameter, DataSourceField, DataSourceKind, DataSourceNode, DatePart, DeclaredField, DefinitionRunMode, DefinitionStatus, Diagnostic, DiagnosticPath, DiagnosticPathSegment, DiagnosticSeverity, DpeAnyNode, DpeApiErrorCategory, DpeBuilderHttpConfig, DpeCanvasEdge, DpeCanvasNode, DpeCanvasPort, DpeCapabilities, DpeColumnInfo, DpeCommandAvailability, DpeCompileResult, DpeCompiledWriteback, DpeDefinition, DpeDefinitionSummary, DpeEnvironment, DpeExtensible, DpeExtensionData, DpeFieldMappingInfo, DpeGraph, DpeGraphEdge, DpeGraphNode, DpeInputPort, DpeLayoutDirection, DpeLayoutEdgeInput, DpeLayoutNodeInput, DpeLayoutOptions, DpeLayoutPosition, DpeLocatedNode, DpeNode, DpeNodeCategory, DpeNodeCollectionMap, DpeNodeCollectionName, DpeNodeDiagnostics, DpeNodeIconFamily, DpeNodePaletteGroup, DpeNodePosition, DpeNodeSchemaInfo, DpeOptionalPrimitive, DpeParameter, DpeParameterValue, DpeRect, DpeSourceReference, DpeSourceSlot, DpeTableState, DpeValidateResult, DpeWritebackStep, ExpressionField, FieldDescriptor, FieldRelationship, FilterCriterion, FilterNode, FilterOperator, ForecastAccuracy, ForecastAggregationField, ForecastGroupField, ForecastModelType, ForecastNode, ForecastPeriodType, HierarchyPathNode, JoinKey, JoinKind, JoinNode, JoinResultField, JsonArtifactOptions, LogicalType, OrderByField, ParameterRole, SortDirection, SqlDialectKind, SqlParameterValue, SqlStatement, TableDescriptor, TableLookupOutcome, TableLookupResult, TableSummary, TransformKind, TransformNode, WritebackFieldMapping, WritebackFieldRole, WritebackNode, WritebackOperation, WritebackTargetKind };
3900
+ export { DPE_API_ERROR_FALLBACK_MESSAGE, DPE_BUILDER_HTTP_CONFIG, DPE_CATALOG_UNAVAILABLE, DPE_DATA_SOURCE_CONDITIONS, DPE_DIALECT_LABELS, DPE_FILTER_CONDITIONS, DPE_HIERARCHY_PATH_CONDITIONS, DPE_JOIN_CONDITIONS, DPE_LAYOUT_KEY, DPE_NODE_CATEGORIES, DPE_NODE_COLLECTIONS, DPE_NODE_HEIGHT, DPE_NODE_ICON_PATHS, DPE_NODE_NOT_COMPILABLE, DPE_SOURCE_SLOTS, DPE_TRANSFORM_CONDITIONS, DPE_WRITEBACK_CONDITIONS, DpeApiError, DpeBuilderApi, DpeBuilderComponent, DpeCanvasComponent, DpeCatalogComponent, DpeCatalogStore, DpeColumnTypeEditorComponent, DpeDiagnosticsPanelComponent, DpeDocumentStore, DpeExpressionEditorComponent, DpeFormulaCatalogStore, DpeLayoutService, DpeMetadataStore, DpeNodeDialogComponent, DpeNodeFactsComponent, DpeNodeIconComponent, DpeNodeInspectorBase, DpeNodeInspectorComponent, DpeNodePaletteComponent, DpeSchemaPanelComponent, DpeSelectValueDirective, DpeSqlPreviewComponent, DpeValidationService, HttpDpeBuilderApi, diagnosticPathToString, dpeAllNodes, dpeBuildGraph, dpeCountReferences, dpeCreateCommandAvailability, dpeCreateNode, dpeDeclares, dpeDefinitionLevelDiagnostics, dpeDiagnosticField, dpeDiagnosticLocationLabel, dpeDiagnosticNodeName, dpeDiagnosticTargetsItem, dpeEdgeId, dpeEmptyDefinition, dpeExpressionFormLabel, dpeExpressionFormPrompt, dpeExpressionFormSupport, dpeFieldVisibility, dpeFindNode, dpeFormulaCatalogOutcome, dpeFormulaCatalogSignature, dpeFormulaCatalogSize, dpeGroupDiagnosticsByNode, dpeHasCompleteLayout, dpeInputPortId, dpeInputPorts, dpeIsDialectDiagnostic, dpeIsNotCompilable, dpeIsPrimitiveAvailable, dpeIsRectFullyVisible, dpeKnownNodeNames, dpeNodeCategory, dpeNodeIconFamily, dpeNodeIconFamilyClass, dpeNodeIconPaths, dpeNodeId, dpeNodeSourceReferences, dpeNodeSubtitle, dpeNodeWidth, dpeNodeWidthClass, dpeOutputPortId, dpeParseInputPortId, dpeParseNodeId, dpeParseOutputPortId, dpeProposeNodeName, dpeProposeWritebackSequence, dpePruneInapplicable, dpeReadCapabilities, dpeReadNodePosition, dpeRenameNode, dpeWorstSeverity, dpeWriteNodePosition, dpeWriteSourceReference, provideDpeBuilderHttpApi };
3901
+ export type { AggregateField, AggregateFunction, AggregateNode, AppendNode, ArtifactKind, AtomicWritebackNode, AtomicWritebackRelationship, ColumnType, CsvArtifactOptions, CsvDelimiter, CsvSourceOptions, CustomNode, CustomNodeParameter, DataSourceField, DataSourceKind, DataSourceNode, DatePart, DeclaredField, DefinitionRunMode, DefinitionStatus, Diagnostic, DiagnosticPath, DiagnosticPathSegment, DiagnosticSeverity, DpeAnyNode, DpeApiErrorCategory, DpeArtifactColumn, DpeArtifactPlan, DpeBuilderHttpConfig, DpeCanvasEdge, DpeCanvasNode, DpeCanvasPort, DpeCapabilities, DpeColumnInfo, DpeCommandAvailability, DpeCompileResult, DpeCompiledWriteback, DpeConditionalFields, DpeDefinition, DpeDefinitionSummary, DpeEnvironment, DpeExpressionForm, DpeExpressionFormSupport, DpeExtensible, DpeExtensionData, DpeFieldCondition, DpeFieldMappingInfo, DpeFieldVisibility, DpeFormulaCatalog, DpeFormulaCatalogOutcome, DpeFormulaCatalogResult, DpeFormulaFunction, DpeFormulaFunctionParameter, DpeFormulaOperator, DpeFormulaSymbol, DpeFormulaSymbolKind, DpeGraph, DpeGraphEdge, DpeGraphNode, DpeInputPort, DpeLayoutDirection, DpeLayoutEdgeInput, DpeLayoutNodeInput, DpeLayoutOptions, DpeLayoutPosition, DpeLocatedNode, DpeNode, DpeNodeCategory, DpeNodeCollectionMap, DpeNodeCollectionName, DpeNodeDiagnostics, DpeNodeIconFamily, DpeNodePaletteGroup, DpeNodePosition, DpeNodeSchemaInfo, DpeOptionalPrimitive, DpeParameter, DpeParameterValue, DpeRect, DpeSourceReference, DpeSourceSlot, DpeTableState, DpeValidateResult, DpeWritebackStep, ExpressionField, FieldDescriptor, FieldRelationship, FilterCriterion, FilterNode, FilterOperator, ForecastAccuracy, ForecastAggregationField, ForecastGroupField, ForecastModelType, ForecastNode, ForecastPeriodType, HierarchyPathNode, JoinKey, JoinKind, JoinNode, JoinResultField, JsonArtifactOptions, LogicalType, OrderByField, ParameterRole, SortDirection, SqlDialectKind, SqlParameterValue, SqlStatement, TableDescriptor, TableLookupOutcome, TableLookupResult, TableSummary, TransformKind, TransformNode, WritebackFailureHandling, WritebackFieldMapping, WritebackFieldRole, WritebackNode, WritebackOperation, WritebackTargetKind };