@esfaenza/dpe-builder 20.0.1
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/fesm2022/esfaenza-dpe-builder.mjs +8711 -0
- package/fesm2022/esfaenza-dpe-builder.mjs.map +1 -0
- package/index.d.ts +2424 -0
- package/package.json +28 -0
- package/styles/dpe-builder.css +222 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,2424 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { HttpClient } from '@angular/common/http';
|
|
3
|
+
import * as _angular_core from '@angular/core';
|
|
4
|
+
import { InjectionToken, EnvironmentProviders, Signal, AfterViewChecked } from '@angular/core';
|
|
5
|
+
import * as _esfaenza_dpe_builder from '@esfaenza/dpe-builder';
|
|
6
|
+
import { EFMarkerType, EFConnectableSide } from '@foblex/flow';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Modello della definizione DPE — traduzione **letterale** dei record C# di
|
|
10
|
+
* `docs/domain-model.md`.
|
|
11
|
+
*
|
|
12
|
+
* Questi tipi sono allineati **a mano** ai record di `Jace.DPE.Model` (ADR 0007: nessun
|
|
13
|
+
* generatore di tipi, nessuno JSON Schema). Sono due modelli in due linguaggi e il
|
|
14
|
+
* compilatore non dira' mai quando divergono: la fonte di verita' e' `docs/contracts.md` +
|
|
15
|
+
* `docs/domain-model.md`, e chi cambia un record C# aggiorna questo file nello stesso
|
|
16
|
+
* momento.
|
|
17
|
+
*
|
|
18
|
+
* Convenzioni, tutte conseguenza del contratto:
|
|
19
|
+
*
|
|
20
|
+
* - proprieta' in **camelCase**, perche' il JSON prodotto dal backend e' camelCase
|
|
21
|
+
* (`domain-model.md`, convenzioni generali);
|
|
22
|
+
* - gli enum C# diventano **unioni di stringhe letterali** con i nomi esatti dei valori: un
|
|
23
|
+
* `enum` TypeScript non e' assegnabile da una stringa arrivata dalla rete, e un valore
|
|
24
|
+
* numerico non e' cio' che il backend serializza;
|
|
25
|
+
* - le collezioni nel backend non sono mai nulle, ma il JSON le **omette quando vuote**
|
|
26
|
+
* (ADR 0003): qui sono opzionali e chi legge non presume che esistano;
|
|
27
|
+
* - `extensionData` esiste su **ogni** record (**I7**): sono proprieta' JSON non riconosciute,
|
|
28
|
+
* con valori **opachi**. L'editor le trasporta senza interpretarle.
|
|
29
|
+
*
|
|
30
|
+
* Nessuna regola di dominio vive qui: obbligatorieta' condizionali, unicita' dei nomi e
|
|
31
|
+
* compatibilita' dei tipi sono del backend. Le note `condiz.` nei commenti sono descrittive
|
|
32
|
+
* e servono a chi costruira' gli ispettori, non sono validazione.
|
|
33
|
+
*/
|
|
34
|
+
/** Proprieta' JSON non riconosciute, conservate verbatim (**I7**). Valori opachi. */
|
|
35
|
+
type DpeExtensionData = Record<string, unknown>;
|
|
36
|
+
/** Base di ogni record del modello: `ExtensionData` sta su tutti, non solo sulla radice. */
|
|
37
|
+
interface DpeExtensible {
|
|
38
|
+
extensionData?: DpeExtensionData;
|
|
39
|
+
}
|
|
40
|
+
/** I sei tipi logici, nessun altro valore mai (ADR 0002). */
|
|
41
|
+
type LogicalType = 'String' | 'Number' | 'Integer' | 'DateTime' | 'Boolean' | 'Enum';
|
|
42
|
+
interface ColumnType extends DpeExtensible {
|
|
43
|
+
kind: LogicalType;
|
|
44
|
+
/** Condiz.: richiesto per `String` nei campi dichiarati. */
|
|
45
|
+
length?: number;
|
|
46
|
+
/** Solo `Number`. */
|
|
47
|
+
precision?: number;
|
|
48
|
+
/** Condiz.: richiesto per `Number` nei campi dichiarati. */
|
|
49
|
+
scale?: number;
|
|
50
|
+
/** Condiz.: non vuoto quando `kind === 'Enum'`. */
|
|
51
|
+
allowedValues?: string[];
|
|
52
|
+
}
|
|
53
|
+
type SortDirection = 'Ascending' | 'Descending';
|
|
54
|
+
interface OrderByField extends DpeExtensible {
|
|
55
|
+
/** Alias della colonna a monte. */
|
|
56
|
+
columnName: string;
|
|
57
|
+
/** Default `Ascending`. */
|
|
58
|
+
direction?: SortDirection;
|
|
59
|
+
}
|
|
60
|
+
type AggregateFunction = 'Count' | 'CountDistinct' | 'Sum' | 'Min' | 'Max' | 'Avg' | 'StdDev' | 'StdDevPop' | 'Variance' | 'VariancePop';
|
|
61
|
+
/** Base di tutti i nodi. `name` e' univoco nell'intera definizione (**I1**). */
|
|
62
|
+
interface DpeNode extends DpeExtensible {
|
|
63
|
+
name: string;
|
|
64
|
+
label: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* I riferimenti a un nodo a monte sono dichiarati **opzionali** anche dove
|
|
69
|
+
* `domain-model.md` li marca obbligatori, e non e' un ammorbidimento del contratto: e' cio'
|
|
70
|
+
* che il contratto dice. In C# sono `string` con default `null`, l'obbligatorieta' e'
|
|
71
|
+
* verificata dalla validazione e "un modello incompleto e' un fatto normale (l'editor ne
|
|
72
|
+
* produce uno a ogni tasto)". Un nodo appena creato o appena scollegato **non ha** una
|
|
73
|
+
* sorgente: rappresentarla con la stringa vuota sarebbe un valore magico che il backend
|
|
74
|
+
* legge diversamente da un'assenza.
|
|
75
|
+
*/
|
|
76
|
+
type SqlDialectKind = 'Sqlite' | 'SqlServer' | 'PostgreSql' | 'Oracle';
|
|
77
|
+
type DefinitionStatus = 'Active' | 'Inactive';
|
|
78
|
+
type DefinitionRunMode = 'Batch' | 'OnDemand';
|
|
79
|
+
interface DpeDefinition extends DpeExtensible {
|
|
80
|
+
/** Default `1`, sempre serializzato per primo. */
|
|
81
|
+
formatVersion: number;
|
|
82
|
+
name: string;
|
|
83
|
+
label: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
/** Il dialetto e' **parte della definizione** (ADR 0009): cambiarlo e' una migrazione. */
|
|
86
|
+
dialect: SqlDialectKind;
|
|
87
|
+
/** Default `Inactive`. */
|
|
88
|
+
status?: DefinitionStatus;
|
|
89
|
+
/** Default `Batch`. */
|
|
90
|
+
runMode?: DefinitionRunMode;
|
|
91
|
+
/** Default `false`. */
|
|
92
|
+
isTemplate?: boolean;
|
|
93
|
+
parameters?: DpeParameter[];
|
|
94
|
+
/** Obbligatoria (>=1) in una definizione valida; assente in una in lavorazione. */
|
|
95
|
+
dataSources?: DataSourceNode[];
|
|
96
|
+
filters?: FilterNode[];
|
|
97
|
+
joins?: JoinNode[];
|
|
98
|
+
aggregates?: AggregateNode[];
|
|
99
|
+
transforms?: TransformNode[];
|
|
100
|
+
appends?: AppendNode[];
|
|
101
|
+
hierarchyPaths?: HierarchyPathNode[];
|
|
102
|
+
/** Modellati, non compilabili in v1 (`DPE_NODE_NOT_COMPILABLE`). */
|
|
103
|
+
forecasts?: ForecastNode[];
|
|
104
|
+
/** Modellati, non compilabili in v1. */
|
|
105
|
+
customNodes?: CustomNode[];
|
|
106
|
+
/** Obbligatoria (>=1) in una definizione valida. */
|
|
107
|
+
writebacks?: WritebackNode[];
|
|
108
|
+
atomicWritebacks?: AtomicWritebackNode[];
|
|
109
|
+
}
|
|
110
|
+
type ParameterRole = 'Value' | 'Filter' | 'Expression';
|
|
111
|
+
interface DpeParameter extends DpeExtensible {
|
|
112
|
+
name: string;
|
|
113
|
+
label: string;
|
|
114
|
+
description?: string;
|
|
115
|
+
role: ParameterRole;
|
|
116
|
+
/** Condiz.: richiesto quando `role === 'Value'`. */
|
|
117
|
+
valueType?: ColumnType;
|
|
118
|
+
/** Testo, interpretato secondo `valueType`, cultura invariante. */
|
|
119
|
+
defaultValue?: string;
|
|
120
|
+
/** Default `false`; ammesso solo per `role === 'Value'`. */
|
|
121
|
+
isMultiValue?: boolean;
|
|
122
|
+
}
|
|
123
|
+
type DataSourceKind = 'Table' | 'Csv' | 'ExternalDataset';
|
|
124
|
+
type CsvDelimiter = 'Comma' | 'Semicolon' | 'Tab' | 'Pipe' | 'Caret' | 'Backquote';
|
|
125
|
+
interface CsvSourceOptions extends DpeExtensible {
|
|
126
|
+
/** Default `Comma`. */
|
|
127
|
+
delimiter?: CsvDelimiter;
|
|
128
|
+
/** Default `true`. */
|
|
129
|
+
hasHeaderRow?: boolean;
|
|
130
|
+
/** Identificatore opaco risolto dall'host. */
|
|
131
|
+
location: string;
|
|
132
|
+
}
|
|
133
|
+
interface DataSourceField extends DpeExtensible {
|
|
134
|
+
/** Nome del campo nella tabella/file di origine. */
|
|
135
|
+
name: string;
|
|
136
|
+
/** Quando assente l'alias **e'** `name`: la normalizzazione e' del backend. */
|
|
137
|
+
alias?: string;
|
|
138
|
+
/** Condiz.: richiesto per `Csv`/`ExternalDataset`; per `Table` **ignorato**. */
|
|
139
|
+
declaredType?: ColumnType;
|
|
140
|
+
/** Default `false`. */
|
|
141
|
+
isPrimaryKey?: boolean;
|
|
142
|
+
}
|
|
143
|
+
interface DataSourceNode extends DpeNode {
|
|
144
|
+
kind: DataSourceKind;
|
|
145
|
+
/** Condiz.: richiesto per `kind === 'Table'`; nome noto al provider di metadati. */
|
|
146
|
+
tableName?: string;
|
|
147
|
+
/** Obbligatorio (>=1) in un nodo valido. */
|
|
148
|
+
fields?: DataSourceField[];
|
|
149
|
+
/** Condiz.: richiesto per `kind === 'Csv'`. */
|
|
150
|
+
csvOptions?: CsvSourceOptions;
|
|
151
|
+
/** Condiz.: richiesto per `kind === 'ExternalDataset'`. */
|
|
152
|
+
externalDatasetName?: string;
|
|
153
|
+
}
|
|
154
|
+
type FilterOperator = 'Equals' | 'NotEquals' | 'GreaterThan' | 'GreaterThanOrEqual' | 'LessThan' | 'LessThanOrEqual' | 'StartsWith' | 'EndsWith' | 'Contains' | 'DoesNotContain' | 'IsNull' | 'IsNotNull' | 'In' | 'NotIn';
|
|
155
|
+
interface FilterCriterion extends DpeExtensible {
|
|
156
|
+
/** >=1, univoco nel nodo, referenziato da `condition`. */
|
|
157
|
+
sequence: number;
|
|
158
|
+
/** Alias a monte. */
|
|
159
|
+
sourceFieldName: string;
|
|
160
|
+
operator: FilterOperator;
|
|
161
|
+
/** Condiz.: richiesto salvo `IsNull`/`IsNotNull` e salvo `inputVariable` presente. */
|
|
162
|
+
value?: string;
|
|
163
|
+
/** Nome di un `DpeParameter` con `role === 'Value'`; esclusivo con `value`. */
|
|
164
|
+
inputVariable?: string;
|
|
165
|
+
}
|
|
166
|
+
interface FilterNode extends DpeNode {
|
|
167
|
+
sourceName?: string;
|
|
168
|
+
/** Default `false`. */
|
|
169
|
+
isDynamic?: boolean;
|
|
170
|
+
/** Condiz.: richiesto (>=1) quando `isDynamic` e' falso. */
|
|
171
|
+
criteria?: FilterCriterion[];
|
|
172
|
+
/**
|
|
173
|
+
* Condiz.: richiesto quando `isDynamic` e' falso. Combinazione booleana dei `sequence`
|
|
174
|
+
* dei criteri (`1 AND (2 OR 3)`), **non** un'espressione SQL: e' l'unico linguaggio che il
|
|
175
|
+
* backend parsifica davvero.
|
|
176
|
+
*/
|
|
177
|
+
condition?: string;
|
|
178
|
+
/** Condiz.: richiesto quando `isDynamic`; riferisce un parametro con `role === 'Filter'`. */
|
|
179
|
+
filterParameterName?: string;
|
|
180
|
+
}
|
|
181
|
+
type JoinKind = 'Inner' | 'LeftOuter' | 'RightOuter' | 'FullOuter' | 'Lookup';
|
|
182
|
+
interface JoinKey extends DpeExtensible {
|
|
183
|
+
primaryFieldName: string;
|
|
184
|
+
secondaryFieldName: string;
|
|
185
|
+
}
|
|
186
|
+
interface JoinResultField extends DpeExtensible {
|
|
187
|
+
/** Deve essere `primarySourceName` o `secondarySourceName` del nodo. */
|
|
188
|
+
sourceName: string;
|
|
189
|
+
sourceFieldName: string;
|
|
190
|
+
/** Univoco nel nodo (**I1**). */
|
|
191
|
+
alias: string;
|
|
192
|
+
}
|
|
193
|
+
interface JoinNode extends DpeNode {
|
|
194
|
+
primarySourceName?: string;
|
|
195
|
+
secondarySourceName?: string;
|
|
196
|
+
kind: JoinKind;
|
|
197
|
+
/** Obbligatorio (>=1) in un nodo valido. */
|
|
198
|
+
keys?: JoinKey[];
|
|
199
|
+
/** Lo schema di output e' **esplicito**: solo questi campi. */
|
|
200
|
+
fields?: JoinResultField[];
|
|
201
|
+
/** Default `false`; significativo solo per `kind === 'Lookup'`. */
|
|
202
|
+
allowsMultipleLookupValues?: boolean;
|
|
203
|
+
}
|
|
204
|
+
interface AggregateField extends DpeExtensible {
|
|
205
|
+
/** Alias a monte; assente **solo** per `Count` (conteggio righe). */
|
|
206
|
+
sourceFieldName?: string;
|
|
207
|
+
function: AggregateFunction;
|
|
208
|
+
alias: string;
|
|
209
|
+
}
|
|
210
|
+
interface AggregateNode extends DpeNode {
|
|
211
|
+
sourceName?: string;
|
|
212
|
+
/** Alias a monte; vuoto = aggregazione globale su una riga. */
|
|
213
|
+
groupBy?: string[];
|
|
214
|
+
/** Obbligatorio (>=1) in un nodo valido. */
|
|
215
|
+
fields?: AggregateField[];
|
|
216
|
+
}
|
|
217
|
+
type TransformKind = 'Expression' | 'Slice' | 'ComputeRelative';
|
|
218
|
+
interface ExpressionField extends DpeExtensible {
|
|
219
|
+
alias: string;
|
|
220
|
+
/** **SQL nativo del dialetto della definizione** (ADR 0006): passa verbatim. */
|
|
221
|
+
expression: string;
|
|
222
|
+
/** **Autorevole e non verificato** (ADR 0006). */
|
|
223
|
+
declaredType: ColumnType;
|
|
224
|
+
}
|
|
225
|
+
interface TransformNode extends DpeNode {
|
|
226
|
+
sourceName?: string;
|
|
227
|
+
kind: TransformKind;
|
|
228
|
+
/** Condiz.: richiesto (>=1) per `Expression`/`ComputeRelative`, vuoto per `Slice`. */
|
|
229
|
+
expressionFields?: ExpressionField[];
|
|
230
|
+
/** Condiz.: richiesto (>=1) per `Slice`, vuoto altrimenti. */
|
|
231
|
+
droppedFields?: string[];
|
|
232
|
+
/** Solo `ComputeRelative`. */
|
|
233
|
+
partitionBy?: string[];
|
|
234
|
+
/** Solo `ComputeRelative`. */
|
|
235
|
+
orderBy?: OrderByField[];
|
|
236
|
+
}
|
|
237
|
+
interface AppendNode extends DpeNode {
|
|
238
|
+
/** Obbligatorio (>=2) in un nodo valido. */
|
|
239
|
+
sources?: string[];
|
|
240
|
+
/** Default `false`. */
|
|
241
|
+
allowsDisjointSchema?: boolean;
|
|
242
|
+
}
|
|
243
|
+
interface HierarchyPathNode extends DpeNode {
|
|
244
|
+
sourceName?: string;
|
|
245
|
+
/** Chiave del nodo corrente. */
|
|
246
|
+
selfFieldName?: string;
|
|
247
|
+
/** Riferimento al padre. */
|
|
248
|
+
parentFieldName?: string;
|
|
249
|
+
/** Alias della colonna di percorso prodotta (`String`). */
|
|
250
|
+
pathFieldName?: string;
|
|
251
|
+
/** Default `true`. */
|
|
252
|
+
includesSelfValue?: boolean;
|
|
253
|
+
/** Condiz.: richiesto (>=1) quando `isAggregationRequired`. */
|
|
254
|
+
aggregateFields?: AggregateField[];
|
|
255
|
+
/** Default `false`. */
|
|
256
|
+
isAggregationRequired?: boolean;
|
|
257
|
+
rollupPercentageFieldName?: string;
|
|
258
|
+
}
|
|
259
|
+
type ForecastPeriodType = 'Year' | 'YearQuarter' | 'YearMonth' | 'YearWeek' | 'YearMonthDay' | 'FiscalYear' | 'FiscalYearQuarter' | 'FiscalYearMonth' | 'FiscalYearWeek';
|
|
260
|
+
type ForecastModelType = 'Auto' | 'Additive' | 'Multiplicative';
|
|
261
|
+
type ForecastAccuracy = 'None' | 'Eighty' | 'NinetyFive';
|
|
262
|
+
type DatePart = 'Second' | 'Minute' | 'Hour' | 'Day' | 'Week' | 'Month' | 'Quarter' | 'Year';
|
|
263
|
+
interface ForecastAggregationField extends DpeExtensible {
|
|
264
|
+
fieldName: string;
|
|
265
|
+
function: AggregateFunction;
|
|
266
|
+
resultAlias: string;
|
|
267
|
+
}
|
|
268
|
+
interface ForecastGroupField extends DpeExtensible {
|
|
269
|
+
fieldName: string;
|
|
270
|
+
/** Condiz.: richiesto quando il campo e' `DateTime`. */
|
|
271
|
+
datePart?: DatePart;
|
|
272
|
+
}
|
|
273
|
+
/** Modellato per intero, **non compilabile in v1** (`DPE_NODE_NOT_COMPILABLE`). */
|
|
274
|
+
interface ForecastNode extends DpeNode {
|
|
275
|
+
sourceName?: string;
|
|
276
|
+
dateFieldName?: string;
|
|
277
|
+
periodType?: ForecastPeriodType;
|
|
278
|
+
/** Default `1`, ammesso 1..100. */
|
|
279
|
+
periodCount?: number;
|
|
280
|
+
/** Alias della colonna di inizio periodo prodotta. */
|
|
281
|
+
periodStartFieldName?: string;
|
|
282
|
+
/** Default `Auto`. */
|
|
283
|
+
modelType?: ForecastModelType;
|
|
284
|
+
/** `null`/assente = automatica; ammesso 2..24. */
|
|
285
|
+
seasonality?: number;
|
|
286
|
+
/** Default `None`. */
|
|
287
|
+
accuracyPercent?: ForecastAccuracy;
|
|
288
|
+
/** Default `false`. */
|
|
289
|
+
excludesLastPeriod?: boolean;
|
|
290
|
+
/** Obbligatorio (>=1) in un nodo valido. */
|
|
291
|
+
aggregationFields?: ForecastAggregationField[];
|
|
292
|
+
groupFields?: ForecastGroupField[];
|
|
293
|
+
}
|
|
294
|
+
/** Usato dove uno schema si **dichiara** invece di derivarlo. */
|
|
295
|
+
interface DeclaredField extends DpeExtensible {
|
|
296
|
+
name: string;
|
|
297
|
+
type: ColumnType;
|
|
298
|
+
}
|
|
299
|
+
interface CustomNodeParameter extends DpeExtensible {
|
|
300
|
+
name: string;
|
|
301
|
+
value: string;
|
|
302
|
+
}
|
|
303
|
+
/** Modellato per intero, **non compilabile in v1**. */
|
|
304
|
+
interface CustomNode extends DpeNode {
|
|
305
|
+
/** Obbligatorio (>=1) in un nodo valido. */
|
|
306
|
+
sources?: string[];
|
|
307
|
+
extensionName: string;
|
|
308
|
+
extensionNamespace?: string;
|
|
309
|
+
parameters?: CustomNodeParameter[];
|
|
310
|
+
/**
|
|
311
|
+
* Obbligatorio (>=1): senza schema dichiarato la propagazione (**I4**) si interrompe e
|
|
312
|
+
* tutto cio' che sta a valle diventa invalidabile.
|
|
313
|
+
*/
|
|
314
|
+
outputFields?: DeclaredField[];
|
|
315
|
+
}
|
|
316
|
+
type WritebackTargetKind = 'Database' | 'Json' | 'Csv';
|
|
317
|
+
type WritebackOperation = 'Insert' | 'Update' | 'Upsert' | 'Delete';
|
|
318
|
+
type WritebackFieldRole = 'Value' | 'PrimaryKey' | 'QualifierKey';
|
|
319
|
+
interface WritebackFieldMapping extends DpeExtensible {
|
|
320
|
+
/** Condiz.: alias a monte; assente quando `runtimeParameterName` e' presente. */
|
|
321
|
+
sourceFieldName?: string;
|
|
322
|
+
targetFieldName: string;
|
|
323
|
+
/** Il valore viene da un parametro, non dalla riga; esclusivo con `sourceFieldName`. */
|
|
324
|
+
runtimeParameterName?: string;
|
|
325
|
+
/** Default `Value`. */
|
|
326
|
+
role?: WritebackFieldRole;
|
|
327
|
+
relationshipName?: string;
|
|
328
|
+
/** Condiz.: richiesto quando `relationshipName` e' presente. */
|
|
329
|
+
parentName?: string;
|
|
330
|
+
/** Default `false`; se `true`, `sourceFieldName` non e' richiesto. */
|
|
331
|
+
isAutoGenerated?: boolean;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Opzioni dell'artefatto JSON (`contracts.md` §2, «Opzioni degli artefatti»). Sono **solo**
|
|
335
|
+
* scelte di formato, mai di destinazione (ADR 0010).
|
|
336
|
+
*/
|
|
337
|
+
interface JsonArtifactOptions extends DpeExtensible {
|
|
338
|
+
/** Default `false`: JSON compatto, array di oggetti. */
|
|
339
|
+
indented?: boolean;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Opzioni dell'artefatto CSV. Il quoting **non e' configurabile** di proposito: si quota
|
|
343
|
+
* quando serve e si raddoppiano le virgolette, perche' un quoting opzionale produce file che
|
|
344
|
+
* qualcuno non riesce a rileggere.
|
|
345
|
+
*/
|
|
346
|
+
interface CsvArtifactOptions extends DpeExtensible {
|
|
347
|
+
/** Default `Comma`. */
|
|
348
|
+
delimiter?: CsvDelimiter;
|
|
349
|
+
/** Default `true`. */
|
|
350
|
+
includesHeaderRow?: boolean;
|
|
351
|
+
}
|
|
352
|
+
interface WritebackNode extends DpeNode {
|
|
353
|
+
sourceName?: string;
|
|
354
|
+
/** **Determina l'artefatto prodotto**. */
|
|
355
|
+
target: WritebackTargetKind;
|
|
356
|
+
/** >=1, univoco fra tutti i writeback e gli atomic writeback. */
|
|
357
|
+
sequence: number;
|
|
358
|
+
/** Condiz.: richiesto per `target === 'Database'`. */
|
|
359
|
+
tableName?: string;
|
|
360
|
+
/** Condiz.: richiesto per `target === 'Database'`; assente per `Json`/`Csv`. */
|
|
361
|
+
operation?: WritebackOperation;
|
|
362
|
+
/** Obbligatorio (>=1) in un nodo valido. */
|
|
363
|
+
fields?: WritebackFieldMapping[];
|
|
364
|
+
/** Espressione SQL nativa applicata al risultato (ADR 0006). */
|
|
365
|
+
filterCondition?: string;
|
|
366
|
+
/** Condiz.: richiesto per `operation === 'Upsert'`. */
|
|
367
|
+
externalIdFieldName?: string;
|
|
368
|
+
/** Default `false`. */
|
|
369
|
+
onlyChangedRows?: boolean;
|
|
370
|
+
/** Solo `target === 'Json'`. */
|
|
371
|
+
jsonOptions?: JsonArtifactOptions;
|
|
372
|
+
/** Solo `target === 'Csv'`. */
|
|
373
|
+
csvOptions?: CsvArtifactOptions;
|
|
374
|
+
}
|
|
375
|
+
interface AtomicWritebackRelationship extends DpeExtensible {
|
|
376
|
+
/** Nome di un `WritebackNode` con `target === 'Database'`. */
|
|
377
|
+
parentWritebackName?: string;
|
|
378
|
+
parentFieldName?: string;
|
|
379
|
+
childWritebackName?: string;
|
|
380
|
+
childFieldName?: string;
|
|
381
|
+
relationshipName?: string;
|
|
382
|
+
/** Ordine dentro il gruppo atomico. */
|
|
383
|
+
sequence: number;
|
|
384
|
+
}
|
|
385
|
+
interface AtomicWritebackNode extends DpeNode {
|
|
386
|
+
/** Nello stesso spazio di numerazione dei `WritebackNode`. */
|
|
387
|
+
sequence: number;
|
|
388
|
+
/** Obbligatorio (>=1) in un nodo valido. */
|
|
389
|
+
relationships?: AtomicWritebackRelationship[];
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Le collezioni di nodi della radice, con il tipo che ciascuna contiene.
|
|
393
|
+
*
|
|
394
|
+
* Esiste perche' ogni utility che cammina il documento (derivazione degli archi, rinomina,
|
|
395
|
+
* catalogo della palette) deve nominare le collezioni **una volta sola**: una collezione
|
|
396
|
+
* dimenticata in uno dei tre posti non produce nessun errore, produce un arco che non
|
|
397
|
+
* compare o un riferimento che resta rotto dopo una rinomina.
|
|
398
|
+
*/
|
|
399
|
+
interface DpeNodeCollectionMap {
|
|
400
|
+
dataSources: DataSourceNode;
|
|
401
|
+
filters: FilterNode;
|
|
402
|
+
joins: JoinNode;
|
|
403
|
+
aggregates: AggregateNode;
|
|
404
|
+
transforms: TransformNode;
|
|
405
|
+
appends: AppendNode;
|
|
406
|
+
hierarchyPaths: HierarchyPathNode;
|
|
407
|
+
forecasts: ForecastNode;
|
|
408
|
+
customNodes: CustomNode;
|
|
409
|
+
writebacks: WritebackNode;
|
|
410
|
+
atomicWritebacks: AtomicWritebackNode;
|
|
411
|
+
}
|
|
412
|
+
type DpeNodeCollectionName = keyof DpeNodeCollectionMap;
|
|
413
|
+
/** Qualunque nodo della definizione. */
|
|
414
|
+
type DpeAnyNode = DpeNodeCollectionMap[DpeNodeCollectionName];
|
|
415
|
+
/**
|
|
416
|
+
* L'elenco dei nomi di collezione in forma di valore, nell'ordine in cui i nodi si leggono
|
|
417
|
+
* (sorgenti -> trasformazioni -> sink). `keyof` non produce un array a runtime: questo
|
|
418
|
+
* elenco e' l'unico posto in cui vive l'ordine.
|
|
419
|
+
*/
|
|
420
|
+
declare const DPE_NODE_COLLECTIONS: readonly DpeNodeCollectionName[];
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Diagnostiche — traduzione letterale di `Jace.DPE.Diagnostics` (`docs/contracts.md` §1).
|
|
424
|
+
*
|
|
425
|
+
* Tipi allineati **a mano** ai record C# (ADR 0007). L'editor **consuma** queste
|
|
426
|
+
* diagnostiche e non ne produce: nessuna regola di dominio vive nel frontend, quindi in
|
|
427
|
+
* questo file non ci sono ne' codici inventati ne' messaggi ricomposti. Il `message` arriva
|
|
428
|
+
* dal backend, che e' l'unico posto in cui un messaggio viene composto.
|
|
429
|
+
*/
|
|
430
|
+
type DiagnosticSeverity = 'Info' | 'Warning' | 'Error';
|
|
431
|
+
interface DiagnosticPathSegment {
|
|
432
|
+
/** `"filters"`, `"criteria"`, `"fields"`, ... */
|
|
433
|
+
collection?: string;
|
|
434
|
+
/** Nome del nodo/alias, se applicabile. */
|
|
435
|
+
name?: string;
|
|
436
|
+
/** Indice nella collezione, se applicabile. */
|
|
437
|
+
index?: number;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Percorso strutturato del rilievo.
|
|
441
|
+
*
|
|
442
|
+
* **Due forme, entrambe da gestire** (`contracts.md` §1, limite dichiarato): in
|
|
443
|
+
* deserializzazione i nomi dei nodi non sono ancora noti e i segmenti portano solo l'indice
|
|
444
|
+
* (`filters[0].sourceName`); dalla validazione portano il nome (`filters/OnlyActive`). Chi
|
|
445
|
+
* naviga fino al campo deve accettare tutt'e due, altrimenti le diagnostiche del caricamento
|
|
446
|
+
* di un file non sono cliccabili.
|
|
447
|
+
*/
|
|
448
|
+
interface DiagnosticPath {
|
|
449
|
+
segments?: DiagnosticPathSegment[];
|
|
450
|
+
/** Nome della proprieta' in causa, camelCase. */
|
|
451
|
+
field?: string;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* `arguments` e' un dizionario di stringhe con **chiavi canoniche** (`contracts.md` §1):
|
|
455
|
+
* `node`, `field`, `column`, `alias`, `name`, `table`, `parameter`, `dialect`, `construct`,
|
|
456
|
+
* `expected`, `actual`, `value`, `sequence`, `condition`, `token`, `truncated`. L'editor le
|
|
457
|
+
* legge per costruire etichette, non per riscrivere il messaggio.
|
|
458
|
+
*/
|
|
459
|
+
interface Diagnostic {
|
|
460
|
+
/** `DiagnosticCodes.*` del backend. Il frontend non ne dichiara l'elenco: e' del backend. */
|
|
461
|
+
code: string;
|
|
462
|
+
severity: DiagnosticSeverity;
|
|
463
|
+
path?: DiagnosticPath;
|
|
464
|
+
arguments?: Record<string, string>;
|
|
465
|
+
/** Derivato da `code` + `arguments`, cultura invariante. */
|
|
466
|
+
message: string;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* L'unico codice che significa "hai fatto bene, siamo noi": nodo valido ma non ancora
|
|
470
|
+
* compilabile (`Forecast`, `CustomNode`, costrutto non supportato — **I10**). Va distinto
|
|
471
|
+
* visivamente dai `DPE_MODEL_*`, che invece l'utente deve correggere.
|
|
472
|
+
*
|
|
473
|
+
* E' l'unica costante di codice diagnostico che la libreria dichiara, e non e' una
|
|
474
|
+
* duplicazione del dominio: e' la sola distinzione che cambia **come si rende** un rilievo.
|
|
475
|
+
*/
|
|
476
|
+
declare const DPE_NODE_NOT_COMPILABLE = "DPE_NODE_NOT_COMPILABLE";
|
|
477
|
+
/** Rappresentazione testuale del percorso, nella forma usata dai messaggi del backend. */
|
|
478
|
+
declare function diagnosticPathToString(path: DiagnosticPath | undefined): string;
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Tipi di richiesta/risposta del service DPE — traduzione letterale di `docs/contracts.md`
|
|
482
|
+
* §2 (provider di metadati), §3 (SQL emesso) e §5 (il service).
|
|
483
|
+
*
|
|
484
|
+
* Allineati **a mano** ai record C# (ADR 0007). Cio' che non e' trasportabile non c'e':
|
|
485
|
+
* `DpeContext` porta i provider dell'host (`ITableMetadataProvider`, `IDataQueryProvider`,
|
|
486
|
+
* `IArtifactSink`, `ILogger`, `IClock`) e vive **dentro** il backend, quindi non ha un
|
|
487
|
+
* corrispettivo TypeScript. Lo stesso vale per `Execute`: l'editor non esegue, non
|
|
488
|
+
* materializza artefatti e non ha bisogno di `DpeExecuteResult`.
|
|
489
|
+
*/
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Cio' che l'ambiente ospite **dichiara** all'editor. Non e' un tipo del backend C#: `IDpeService`
|
|
493
|
+
* non cambia (ADR 0017), e l'host lo compone con cio' che gia' sa della propria installazione.
|
|
494
|
+
*
|
|
495
|
+
* Nasce con un solo campo e si estende **per aggiunta**: e' il posto previsto per i fatti
|
|
496
|
+
* dell'ambiente, non un contenitore da riempire in anticipo.
|
|
497
|
+
*/
|
|
498
|
+
interface DpeEnvironment {
|
|
499
|
+
/** Il dialetto del database di destinazione. Dichiarato, mai scelto dall'utente dell'editor. */
|
|
500
|
+
readonly dialect: SqlDialectKind;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Riga di catalogo: identita' e fatti che l'ospite conosce **senza** caricare la definizione.
|
|
504
|
+
*
|
|
505
|
+
* Distinto da `DpeDefinition` per costruzione, e non per comodita': elencare non deve costare N
|
|
506
|
+
* caricamenti completi. Non ha un corrispettivo in `IDpeService` e non deve averlo — il service
|
|
507
|
+
* valida, compila ed esegue; dove le definizioni vivano e' dell'ospite (ADR 0007), che non ha
|
|
508
|
+
* ne' orologio ne' archiviazione lato libreria.
|
|
509
|
+
*
|
|
510
|
+
* I quattro campi in coda sono facoltativi in senso pieno: assenti, la riga **non li mostra e
|
|
511
|
+
* non li stima**. Contare i nodi lato client vorrebbe dire caricare tutte le definizioni per
|
|
512
|
+
* disegnare un elenco, e dedurre `updatedAt` e' impossibile.
|
|
513
|
+
*/
|
|
514
|
+
interface DpeDefinitionSummary {
|
|
515
|
+
/** La chiave. Non esiste un id distinto dal nome (ADR 0019): rinominare e' cambiare chiave. */
|
|
516
|
+
name: string;
|
|
517
|
+
label: string;
|
|
518
|
+
description?: string;
|
|
519
|
+
dialect: SqlDialectKind;
|
|
520
|
+
status?: DefinitionStatus;
|
|
521
|
+
runMode?: DefinitionRunMode;
|
|
522
|
+
isTemplate?: boolean;
|
|
523
|
+
/** ISO 8601. Lo scrive l'ospite: la libreria non ha orologio. Assente = non mostrato. */
|
|
524
|
+
updatedAt?: string;
|
|
525
|
+
updatedBy?: string;
|
|
526
|
+
/** Numero di nodi. Lo conta l'ospite, **mai** il client. Assente = non mostrato. */
|
|
527
|
+
nodeCount?: number;
|
|
528
|
+
/**
|
|
529
|
+
* Esito dell'ultima validazione **noto all'ospite**: riportato, non ricalcolato. Puo' essere
|
|
530
|
+
* vecchio, quindi la riga lo mostra come stato noto e non come verita' — il frontend non
|
|
531
|
+
* valida nulla, e dedurlo qui sarebbe una validazione fatta dal client per interposta persona.
|
|
532
|
+
*/
|
|
533
|
+
hasErrors?: boolean;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Tre esiti, **non due** (ADR 0004): "dichiarata", "dichiarata senza campi" e
|
|
537
|
+
* "sconosciuta" sono situazioni diverse e l'editor le mostra diverse. Chi implementa
|
|
538
|
+
* l'interfaccia non appiattisce `Unknown` in una lista di campi vuota.
|
|
539
|
+
*/
|
|
540
|
+
type TableLookupOutcome = 'Declared' | 'DeclaredWithoutFields' | 'Unknown';
|
|
541
|
+
interface TableSummary {
|
|
542
|
+
name: string;
|
|
543
|
+
description?: string;
|
|
544
|
+
}
|
|
545
|
+
interface FieldRelationship {
|
|
546
|
+
targetTableName: string;
|
|
547
|
+
targetFieldName: string;
|
|
548
|
+
}
|
|
549
|
+
interface FieldDescriptor {
|
|
550
|
+
name: string;
|
|
551
|
+
description?: string;
|
|
552
|
+
type: ColumnType;
|
|
553
|
+
isKey: boolean;
|
|
554
|
+
isNullable: boolean;
|
|
555
|
+
/** Assente quando il campo non e' una relazione. */
|
|
556
|
+
relationship?: FieldRelationship;
|
|
557
|
+
}
|
|
558
|
+
interface TableDescriptor {
|
|
559
|
+
name: string;
|
|
560
|
+
description?: string;
|
|
561
|
+
fields?: FieldDescriptor[];
|
|
562
|
+
}
|
|
563
|
+
interface TableLookupResult {
|
|
564
|
+
outcome: TableLookupOutcome;
|
|
565
|
+
/** Presente solo con `outcome === 'Declared'`. */
|
|
566
|
+
table?: TableDescriptor;
|
|
567
|
+
}
|
|
568
|
+
interface SqlParameterValue {
|
|
569
|
+
/** Senza prefisso di dialetto: `"p0"`, `"param_StartDate"`. */
|
|
570
|
+
name: string;
|
|
571
|
+
type: LogicalType;
|
|
572
|
+
/** `null` ammesso. Valore opaco per l'editor, che lo mostra e non lo interpreta. */
|
|
573
|
+
value: unknown;
|
|
574
|
+
}
|
|
575
|
+
interface SqlStatement {
|
|
576
|
+
/** Porta i marcatori nella forma del dialetto (`@p0`, `:p0`, `$1`). */
|
|
577
|
+
text: string;
|
|
578
|
+
parameters?: SqlParameterValue[];
|
|
579
|
+
}
|
|
580
|
+
interface DpeColumnInfo {
|
|
581
|
+
name: string;
|
|
582
|
+
type: ColumnType;
|
|
583
|
+
/**
|
|
584
|
+
* Informativa (**I4**): serve alla vista dello schema, non blocca la compilazione. Il
|
|
585
|
+
* frontend non la calcola — arriva da qui.
|
|
586
|
+
*/
|
|
587
|
+
isNullable: boolean;
|
|
588
|
+
}
|
|
589
|
+
interface DpeNodeSchemaInfo {
|
|
590
|
+
nodeName: string;
|
|
591
|
+
columns?: DpeColumnInfo[];
|
|
592
|
+
/**
|
|
593
|
+
* `false` = nodo **valido ma non compilabile** (**I10**): e' un limite nostro, non un
|
|
594
|
+
* errore dell'utente, e va reso diverso da un nodo invalido.
|
|
595
|
+
*/
|
|
596
|
+
isCompilable: boolean;
|
|
597
|
+
}
|
|
598
|
+
interface DpeWritebackStep {
|
|
599
|
+
writebackName: string;
|
|
600
|
+
sequence: number;
|
|
601
|
+
target: WritebackTargetKind;
|
|
602
|
+
/** Assente per i target `Json`/`Csv`. */
|
|
603
|
+
operation?: WritebackOperation;
|
|
604
|
+
tableName?: string;
|
|
605
|
+
/**
|
|
606
|
+
* Campo di corrispondenza dell'`Upsert`; assente per ogni altra operazione. E' un
|
|
607
|
+
* `targetFieldName`: si ritrova in `targetMapping` per risalire alla colonna del result set
|
|
608
|
+
* (ADR 0016).
|
|
609
|
+
*/
|
|
610
|
+
externalIdFieldName?: string;
|
|
611
|
+
/** Presente se il writeback appartiene a un gruppo atomico. */
|
|
612
|
+
atomicGroupName?: string;
|
|
613
|
+
/**
|
|
614
|
+
* Dichiarato, **non implementato dalla libreria**: il change tracking e' dell'host
|
|
615
|
+
* (ADR 0011) e non influenza l'SQL generato. Va mostrato come una dichiarazione che l'host
|
|
616
|
+
* deve onorare, non come una cosa che il motore fa.
|
|
617
|
+
*/
|
|
618
|
+
onlyChangedRows?: boolean;
|
|
619
|
+
}
|
|
620
|
+
interface DpeValidateResult {
|
|
621
|
+
hasErrors: boolean;
|
|
622
|
+
/** Esaustive (**I6**): l'elenco completo, non il primo rilievo. */
|
|
623
|
+
diagnostics?: Diagnostic[];
|
|
624
|
+
/** Ordine topologico. */
|
|
625
|
+
schemas?: DpeNodeSchemaInfo[];
|
|
626
|
+
executionOrder?: string[];
|
|
627
|
+
writebackSequence?: DpeWritebackStep[];
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Valore di un parametro di runtime per una compilazione (`DpeParameterValue`).
|
|
631
|
+
*
|
|
632
|
+
* `value` e' **opaco**: il tipo dichiarato del parametro lo conosce il backend, che lo
|
|
633
|
+
* interpreta secondo `ColumnType` in cultura invariante. L'editor lo trasporta e lo mostra,
|
|
634
|
+
* non lo converte.
|
|
635
|
+
*/
|
|
636
|
+
interface DpeParameterValue {
|
|
637
|
+
name: string;
|
|
638
|
+
value: unknown;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Cio' che serve all'host per **eseguire** la scrittura che la libreria non esegue
|
|
642
|
+
* (`contracts.md` §2, «`DpeFieldMappingInfo`»): senza, l'host riceve un result set e non sa
|
|
643
|
+
* quale colonna va in quale campo ne' quale sia la chiave.
|
|
644
|
+
*/
|
|
645
|
+
interface DpeFieldMappingInfo {
|
|
646
|
+
/** Nome della colonna nel result set dello `SqlStatement`. */
|
|
647
|
+
resultColumnName?: string;
|
|
648
|
+
targetFieldName: string;
|
|
649
|
+
role: WritebackFieldRole;
|
|
650
|
+
/** Presente: il valore viene da un parametro, non dalla riga. */
|
|
651
|
+
runtimeParameterName?: string;
|
|
652
|
+
/** La destinazione genera il valore: non e' nel result set. */
|
|
653
|
+
isAutoGenerated?: boolean;
|
|
654
|
+
relationshipName?: string;
|
|
655
|
+
parentName?: string;
|
|
656
|
+
}
|
|
657
|
+
interface DpeCompiledWriteback {
|
|
658
|
+
writebackName: string;
|
|
659
|
+
sequence: number;
|
|
660
|
+
statement: SqlStatement;
|
|
661
|
+
resultColumns?: DpeColumnInfo[];
|
|
662
|
+
/** Vedi {@link DpeFieldMappingInfo}: forma provvisoria. */
|
|
663
|
+
targetMapping?: DpeFieldMappingInfo[];
|
|
664
|
+
}
|
|
665
|
+
interface DpeCompileResult {
|
|
666
|
+
hasErrors: boolean;
|
|
667
|
+
diagnostics?: Diagnostic[];
|
|
668
|
+
databaseWritebacks?: DpeCompiledWriteback[];
|
|
669
|
+
/** SQL di lettura, non ancora eseguito. */
|
|
670
|
+
fileWritebacks?: DpeCompiledWriteback[];
|
|
671
|
+
writebackSequence?: DpeWritebackStep[];
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Quali primitive **opzionali** l'ospite implementa davvero — `contracts.md` §7, normativo.
|
|
676
|
+
*
|
|
677
|
+
* La rilevazione e' per **identita' del metodo**: se il metodo dell'istanza e' ancora quello del
|
|
678
|
+
* prototipo di `DpeBuilderApi`, l'ospite non lo ha sovrascritto e la primitiva non c'e'. E'
|
|
679
|
+
* esatta, non richiede una primitiva di interrogazione e non aggiunge un giro di rete.
|
|
680
|
+
*
|
|
681
|
+
* Perche' un solo posto: la disponibilita' va saputa **prima del clic**. Lo schema precedente —
|
|
682
|
+
* partire da «disponibile» e scoprire l'assenza dal primo `MissingService` — mostra un comando
|
|
683
|
+
* attivo che fallisce alla pressione, cioe' insegna a non fidarsi dei bottoni, e per giunta
|
|
684
|
+
* costringe ogni consumatore a ripetere lo stesso trattamento dell'errore.
|
|
685
|
+
*
|
|
686
|
+
* Regola per chi implementa un host (normativa, `contracts.md` §7): **chi non supporta una
|
|
687
|
+
* primitiva non la sovrascrive**. Una sovrascrittura che lancia subito non equivale all'assenza —
|
|
688
|
+
* l'editor la considera disponibile e mostra il comando attivo.
|
|
689
|
+
*
|
|
690
|
+
* **Dichiarazione sottrattiva (ADR 0020).** Da quando la libreria spedisce un client HTTP che
|
|
691
|
+
* implementa tutte e dieci le primitive, l'identita' da sola non basta: chi eredita quel client
|
|
692
|
+
* non puo' dis-sovrascrivere un metodo. Disponibile diventa quindi «**sovrascritta** e **non
|
|
693
|
+
* elencata** in `unsupportedPrimitives`». La seconda meta' e' solo sottrattiva — non rende
|
|
694
|
+
* disponibile cio' che non e' implementato — e resta calcolata in questo file e in nessun altro.
|
|
695
|
+
*/
|
|
696
|
+
|
|
697
|
+
/** Le primitive che un ambiente ospite puo' legittimamente non offrire. */
|
|
698
|
+
type DpeOptionalPrimitive = 'compilePreview' | 'load' | 'save' | 'getEnvironment' | 'listDefinitions' | 'createDefinition' | 'deleteDefinition';
|
|
699
|
+
declare function dpeIsPrimitiveAvailable(api: DpeBuilderApi, primitive: DpeOptionalPrimitive): boolean;
|
|
700
|
+
/** L'insieme delle primitive disponibili: comodo per fotografarlo una volta alla costruzione. */
|
|
701
|
+
interface DpeCapabilities {
|
|
702
|
+
readonly compilePreview: boolean;
|
|
703
|
+
readonly load: boolean;
|
|
704
|
+
readonly save: boolean;
|
|
705
|
+
readonly getEnvironment: boolean;
|
|
706
|
+
readonly listDefinitions: boolean;
|
|
707
|
+
readonly createDefinition: boolean;
|
|
708
|
+
readonly deleteDefinition: boolean;
|
|
709
|
+
}
|
|
710
|
+
declare function dpeReadCapabilities(api: DpeBuilderApi): DpeCapabilities;
|
|
711
|
+
/**
|
|
712
|
+
* Disponibilita' di un comando, con **il motivo** quando manca: un bottone disabilitato che non
|
|
713
|
+
* dice perche' manda a cercare un guasto che non c'e'.
|
|
714
|
+
*/
|
|
715
|
+
interface DpeCommandAvailability {
|
|
716
|
+
readonly isAvailable: boolean;
|
|
717
|
+
/** Presente **solo** quando il comando non e' disponibile. Va nel `title` del bottone. */
|
|
718
|
+
readonly reason?: string;
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Il comando di **creazione** e' l'unico che dipende da **due** primitive
|
|
722
|
+
* (`contracts.md` §7, normativo): `createDefinition` per scrivere, e `getEnvironment` perche' il
|
|
723
|
+
* dialetto della definizione nuova viene dall'ambiente (ADR 0017).
|
|
724
|
+
*
|
|
725
|
+
* Perche' senza `getEnvironment` si disabilita invece di ripiegare su un dialetto qualsiasi: una
|
|
726
|
+
* definizione creata per il dialetto sbagliato porta espressioni SQL native (ADR 0006) da
|
|
727
|
+
* riscrivere tutte, e chiederlo all'utente e' proprio la scelta che l'ADR 0017 ha tolto. Un
|
|
728
|
+
* comando disabilitato che dice perche' e' meglio di entrambe; il rimedio per l'ospite e' una
|
|
729
|
+
* riga, implementare `getEnvironment`.
|
|
730
|
+
*
|
|
731
|
+
* Sta qui e non dentro un componente per la stessa ragione delle altre: la disponibilita' si sa
|
|
732
|
+
* **prima del clic**, e in un solo posto.
|
|
733
|
+
*/
|
|
734
|
+
declare function dpeCreateCommandAvailability(capabilities: DpeCapabilities): DpeCommandAvailability;
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* L'unica porta verso il backend — `docs/contracts.md` §7.
|
|
738
|
+
*
|
|
739
|
+
* **Non esiste un documento di endpoint: il contratto e' questa classe astratta** (ADR 0007).
|
|
740
|
+
* Fa anche da token di dependency injection: chi integra l'editor fornisce una
|
|
741
|
+
* implementazione e la registra come provider di `DpeBuilderApi`.
|
|
742
|
+
*
|
|
743
|
+
* Due conseguenze da non aggirare:
|
|
744
|
+
*
|
|
745
|
+
* 1. **questo file non conosce HTTP.** Nessun `HttpClient`, nessun `fetch`, nessun URL qui ne'
|
|
746
|
+
* in nessuno store o componente. L'ADR 0020 ha spostato il client HTTP **dentro** la libreria
|
|
747
|
+
* (`lib/api/http-dpe-builder-api.ts`), quindi la regola non e' piu' «zero HTTP in
|
|
748
|
+
* `projects/dpe-builder`» ma «zero HTTP fuori da quel file»: e' *una* implementazione fra le
|
|
749
|
+
* possibili, non la definizione del contratto, che resta questa classe;
|
|
750
|
+
* 2. **un dato nuovo dal backend e' un metodo nuovo qui**, mai una chiamata dentro un
|
|
751
|
+
* componente.
|
|
752
|
+
*
|
|
753
|
+
* I metodi con implementazione di default rifiutano con `DpeApiError('MissingService', ...)`:
|
|
754
|
+
* un ambiente che non li espone lascia l'editor funzionante con il singolo comando
|
|
755
|
+
* disabilitato. Un'anteprima SQL non disponibile disabilita l'anteprima, non l'editor.
|
|
756
|
+
*
|
|
757
|
+
* I metodi restituiscono `Observable` perche' l'I/O del frontend e' asincrono per natura. Il
|
|
758
|
+
* vincolo di sincronia della libreria C# riguarda il backend: qui si traduce solo nel fatto
|
|
759
|
+
* che una chiamata occupa il chiamante finche' non termina, quindi chi la invoca mostra
|
|
760
|
+
* l'attesa e non incatena una validazione a ogni battitura senza debounce.
|
|
761
|
+
*/
|
|
762
|
+
|
|
763
|
+
declare abstract class DpeBuilderApi {
|
|
764
|
+
/**
|
|
765
|
+
* Primitive opzionali che **questo ambiente non serve**, dichiarate dall'ospite (ADR 0020,
|
|
766
|
+
* `contracts.md` §7).
|
|
767
|
+
*
|
|
768
|
+
* Perche' esiste, dato che la rilevazione per identita' del metodo bastava: da quando la
|
|
769
|
+
* libreria spedisce un client HTTP che implementa **tutte** le primitive
|
|
770
|
+
* (`HttpDpeBuilderApi`), chi lo eredita non ha modo di *dis*-sovrascrivere un metodo. Si
|
|
771
|
+
* ritroverebbe comandi attivi su endpoint che il suo backend non serve — esattamente il
|
|
772
|
+
* difetto che la regola dell'identita' esisteva per prevenire.
|
|
773
|
+
*
|
|
774
|
+
* E' **solo sottrattiva**: non rende disponibile cio' che non e' implementato, e il tipo
|
|
775
|
+
* `DpeOptionalPrimitive` le impedisce di nominare le tre primitive obbligatorie. Vuoto per
|
|
776
|
+
* default, cosi' un'implementazione che non la tocca conserva esattamente il comportamento
|
|
777
|
+
* di prima.
|
|
778
|
+
*
|
|
779
|
+
* Chi la usa deve anche rigettare la primitiva con `DpeApiError('MissingService', ...)`
|
|
780
|
+
* **senza emettere la richiesta**: sapere in anticipo che un servizio non c'e' e chiederglielo
|
|
781
|
+
* comunque e' il difetto che questa dichiarazione evita.
|
|
782
|
+
*/
|
|
783
|
+
readonly unsupportedPrimitives: readonly DpeOptionalPrimitive[];
|
|
784
|
+
/**
|
|
785
|
+
* `IDpeService.Validate` — **non produce SQL e non legge dati** (`contracts.md` §5). E' la
|
|
786
|
+
* primitiva del feedback durante l'editing: diagnostiche, schemi di ogni nodo, ordine di
|
|
787
|
+
* esecuzione e sequenza dei writeback in una sola risposta.
|
|
788
|
+
*
|
|
789
|
+
* Prende la definizione **in lavorazione**, non quella salvata: cio' che l'editor mostra
|
|
790
|
+
* deve riferirsi a cio' che l'utente sta scrivendo. Va invocata con debounce.
|
|
791
|
+
*/
|
|
792
|
+
abstract validate(definition: DpeDefinition): Observable<DpeValidateResult>;
|
|
793
|
+
/**
|
|
794
|
+
* `IDpeService.GetTables` — passaggio diretto al provider di metadati dell'host, **non ai
|
|
795
|
+
* cataloghi del database** (`contracts.md` §2). L'elenco puo' essere grande: chi lo consuma
|
|
796
|
+
* carica in modo asincrono e filtra, non lo riversa in un `<select>`.
|
|
797
|
+
*/
|
|
798
|
+
abstract getTables(): Observable<TableSummary[]>;
|
|
799
|
+
/**
|
|
800
|
+
* `IDpeService.GetTable` — i **tre** esiti dell'ADR 0004 restano distinti fino alla UI:
|
|
801
|
+
* `Declared`, `DeclaredWithoutFields` ("la tabella c'e', i campi non li so") e `Unknown`.
|
|
802
|
+
* Appiattirli e' esattamente cio' che il contratto vieta.
|
|
803
|
+
*/
|
|
804
|
+
abstract getTable(tableName: string): Observable<TableLookupResult>;
|
|
805
|
+
/**
|
|
806
|
+
* `IDpeService.Compile` — l'anteprima dell'SQL generato, in sola lettura.
|
|
807
|
+
*
|
|
808
|
+
* Opzionale: senza di essa il comando di anteprima si disabilita e il resto dell'editor
|
|
809
|
+
* continua a funzionare.
|
|
810
|
+
*
|
|
811
|
+
* `parameterValues` e' opzionale e corrisponde a `DpeCompileRequest.ParameterValues`.
|
|
812
|
+
* Ometterlo e' un comportamento **dichiarato**, non un ripiego: l'anteprima usa allora i
|
|
813
|
+
* `defaultValue` dei parametri. Passarli serve perche' senza di essi l'anteprima resterebbe
|
|
814
|
+
* muta proprio sui parametri **privi** di default, cioe' quelli che l'utente vuole provare.
|
|
815
|
+
*/
|
|
816
|
+
compilePreview(definition: DpeDefinition, parameterValues?: DpeParameterValue[]): Observable<DpeCompileResult>;
|
|
817
|
+
/**
|
|
818
|
+
* Caricamento di una definizione per nome. Opzionale: dove non c'e', l'editor lavora sulla
|
|
819
|
+
* definizione che gli viene passata dall'ospite.
|
|
820
|
+
*
|
|
821
|
+
* La deserializzazione (`IDpeService.Deserialize`) resta del backend: qui arriva un
|
|
822
|
+
* documento già letto, con le sue eventuali diagnostiche già emesse.
|
|
823
|
+
*/
|
|
824
|
+
load(name: string): Observable<DpeDefinition>;
|
|
825
|
+
/** Salvataggio. Opzionale: un editor in sola lettura e' un uso legittimo. */
|
|
826
|
+
save(definition: DpeDefinition): Observable<void>;
|
|
827
|
+
/**
|
|
828
|
+
* La dichiarazione dell'ambiente (ADR 0017). Oggi porta **solo** il dialetto del database di
|
|
829
|
+
* destinazione, che e' un fatto dell'installazione e non una preferenza dell'autore della
|
|
830
|
+
* definizione: per questo l'editor non offre nessun comando per cambiarlo.
|
|
831
|
+
*
|
|
832
|
+
* Cosa l'editor fa con la risposta, e cosa non fa: mostra il dialetto in sola lettura e, se
|
|
833
|
+
* differisce da quello della definizione (ADR 0009: e' li' che vive, ed e' da li' che il
|
|
834
|
+
* backend lo legge), **lo segnala senza correggere**. Riscrivere `definition.dialect` sarebbe
|
|
835
|
+
* una migrazione silenziosa di tutte le espressioni SQL native (ADR 0006), per giunta eseguita
|
|
836
|
+
* all'apertura e capace di marcare come «modificata» una definizione che nessuno ha toccato.
|
|
837
|
+
*
|
|
838
|
+
* Opzionale come le altre: dove manca, l'editor mostra il dialetto della definizione e non
|
|
839
|
+
* dice nient'altro.
|
|
840
|
+
*/
|
|
841
|
+
getEnvironment(): Observable<DpeEnvironment>;
|
|
842
|
+
/**
|
|
843
|
+
* Elenco delle definizioni disponibili — **catalogo** (ADR 0019). Opzionale: dove manca, un
|
|
844
|
+
* catalogo montato dall'ospite mostra il perche' invece di un elenco vuoto.
|
|
845
|
+
*
|
|
846
|
+
* **Nessun oggetto di interrogazione**, di proposito: niente ricerca, niente paginazione. Il
|
|
847
|
+
* filtro di testo del catalogo e' locale sui sommari ricevuti, e aggiungere una query in
|
|
848
|
+
* seguito e' additivo. Un parametro che nessuno esercita e' un parametro che nessuno verifica.
|
|
849
|
+
*
|
|
850
|
+
* L'ospite e' tenuto a restituire i sommari in un **ordine stabile**: il catalogo non riordina,
|
|
851
|
+
* perche' riordinare lato client combatterebbe una scelta che l'ospite ha gia' fatto.
|
|
852
|
+
*/
|
|
853
|
+
listDefinitions(): Observable<DpeDefinitionSummary[]>;
|
|
854
|
+
/**
|
|
855
|
+
* Creazione di una definizione. Opzionale.
|
|
856
|
+
*
|
|
857
|
+
* **Restituisce il sommario, non `void`**: l'ospite puo' aver normalizzato il nome, e chi crea
|
|
858
|
+
* apre **il nome tornato**, non quello digitato. Il risultato di una scrittura non si crede
|
|
859
|
+
* sulla parola.
|
|
860
|
+
*
|
|
861
|
+
* Distinta da `save` per una ragione di merito: `save(definition)` significa «scrivi questa
|
|
862
|
+
* definizione» e non distingue inserimento da aggiornamento, quindi farle significare anche
|
|
863
|
+
* «creala» toglierebbe all'ospite l'unico posto in cui puo' **rifiutare un nome duplicato**.
|
|
864
|
+
*
|
|
865
|
+
* Non esiste una primitiva di duplicazione: duplicare e' `load` piu' `createDefinition`, e il
|
|
866
|
+
* comando vive nel catalogo.
|
|
867
|
+
*/
|
|
868
|
+
createDefinition(definition: DpeDefinition): Observable<DpeDefinitionSummary>;
|
|
869
|
+
/**
|
|
870
|
+
* Cancellazione per nome. Opzionale: un catalogo di sola lettura e' un uso legittimo.
|
|
871
|
+
*
|
|
872
|
+
* Non esiste una primitiva di rinomina: rinominare cambia la chiave, quindi e'
|
|
873
|
+
* creare-e-cancellare, cioe' una decisione di storage che e' dell'ospite (ADR 0019).
|
|
874
|
+
*/
|
|
875
|
+
deleteDefinition(name: string): Observable<void>;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Errore categorizzato del contratto verso il backend.
|
|
880
|
+
*
|
|
881
|
+
* L'editor si comporta in base alla **categoria**, mai leggendo il messaggio: chi implementa
|
|
882
|
+
* {@link DpeBuilderApi} traduce l'errore di trasporto (status HTTP, payload, timeout) in un
|
|
883
|
+
* `DpeApiError`, e da lì in poi nella libreria non esiste piu' nessuna nozione di HTTP
|
|
884
|
+
* (ADR 0007).
|
|
885
|
+
*/
|
|
886
|
+
/**
|
|
887
|
+
* Le categorie sono **tre** e chiuse, perche' sono tre comportamenti diversi della UI:
|
|
888
|
+
*
|
|
889
|
+
* - `MissingService`: la primitiva non e' implementata su questo ambiente. Degrada il
|
|
890
|
+
* **singolo comando** (l'anteprima SQL si disabilita), non l'editor;
|
|
891
|
+
* - `Transport`: la chiamata non e' arrivata o non e' tornata. Si puo' ritentare;
|
|
892
|
+
* - `Backend`: il backend ha risposto rifiutando. Non si ritenta da soli.
|
|
893
|
+
*
|
|
894
|
+
* Un errore di validazione **non e'** una categoria: le diagnostiche sono un *risultato*
|
|
895
|
+
* (`DpeValidateResult.diagnostics`), non un fallimento — e' la stessa regola del backend,
|
|
896
|
+
* dove il fallimento previsto e' un risultato e non un'eccezione.
|
|
897
|
+
*/
|
|
898
|
+
type DpeApiErrorCategory = 'MissingService' | 'Transport' | 'Backend';
|
|
899
|
+
declare class DpeApiError extends Error {
|
|
900
|
+
readonly category: DpeApiErrorCategory;
|
|
901
|
+
/** Payload di dettaglio dell'host, opaco per la libreria. */
|
|
902
|
+
readonly details?: unknown | undefined;
|
|
903
|
+
constructor(category: DpeApiErrorCategory, message: string,
|
|
904
|
+
/** Payload di dettaglio dell'host, opaco per la libreria. */
|
|
905
|
+
details?: unknown | undefined);
|
|
906
|
+
static is(value: unknown): value is DpeApiError;
|
|
907
|
+
/** Vero quando il comando corrispondente va disabilitato invece che segnalato. */
|
|
908
|
+
static isMissingService(value: unknown): boolean;
|
|
909
|
+
}
|
|
910
|
+
/** Messaggi di ripiego: il `message` dell'host, quando c'e', ha la precedenza. */
|
|
911
|
+
declare const DPE_API_ERROR_FALLBACK_MESSAGE: Record<DpeApiErrorCategory, string>;
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* Implementazione HTTP di {@link DpeBuilderApi}, sulle rotte **normative** di
|
|
915
|
+
* `docs/contracts.md` §7-bis.
|
|
916
|
+
*
|
|
917
|
+
* Vive nella libreria per decisione del committente (ADR 0020, che revisiona la sola clausola
|
|
918
|
+
* dell'ADR 0007 sulla collocazione): l'integrazione e' due righe invece che un file da copiare.
|
|
919
|
+
* Il prezzo, accettato e scritto: **le rotte sono contratto pubblico**, e cambiarne una e' un
|
|
920
|
+
* breaking change. Da qui in poi questa classe non e' «un esempio» — una classe esportata da una
|
|
921
|
+
* libreria viene usata in produzione a prescindere da come la chiamiamo nel commento, e chiamarla
|
|
922
|
+
* esempio servirebbe solo a esentarla dai test.
|
|
923
|
+
*
|
|
924
|
+
* Resta vero cio' che conta dell'ADR 0007: **il contratto e' la classe astratta**, non questo
|
|
925
|
+
* client. Nessun componente e nessuno store della libreria lo importa. Chi ha rotte diverse ha due
|
|
926
|
+
* strade, e nessuna tocca l'editor:
|
|
927
|
+
*
|
|
928
|
+
* 1. **estendere questa classe** e sovrascrivere i soli metodi divergenti. I punti di estensione
|
|
929
|
+
* sono `protected` di proposito: `url()` per il prefisso e la forma del percorso, `segment()`
|
|
930
|
+
* per la codifica, i quattro verbi per il trasporto, `fail()` per la traduzione degli errori,
|
|
931
|
+
* `request()` per cio' che avvolge ogni chiamata;
|
|
932
|
+
* 2. **scrivere un'altra implementazione di `DpeBuilderApi` da zero** — legittima e supportata.
|
|
933
|
+
*
|
|
934
|
+
* Le tre cose che chi legge questo file deve sapere, e che nessun compilatore gli dira':
|
|
935
|
+
*
|
|
936
|
+
* 1. **il corpo e' il documento nudo** dove il backend analizza o archivia la definizione
|
|
937
|
+
* (`validate`, `createDefinition`, `save`). L'unico involucro e' `compilePreview`, perche' li'
|
|
938
|
+
* il corpo porta anche i valori dei parametri. Sbagliare involucro **non produce nessun
|
|
939
|
+
* errore**: un backend che deserializza una `DpeDefinition` da `{definition: …}` non riconosce
|
|
940
|
+
* nessuna proprieta', risponde `200`, e l'editor mostra la validazione di una definizione
|
|
941
|
+
* vuota;
|
|
942
|
+
* 2. **la serializzazione e' camelCase.** I tipi TypeScript sono allineati a mano ai record C#: un
|
|
943
|
+
* backend che risponde in PascalCase non produce nessun errore, produce campi `undefined`;
|
|
944
|
+
* 3. **l'errore di trasporto diventa una categoria.** L'editor si comporta in base alla categoria
|
|
945
|
+
* e non legge mai il messaggio: `MissingService` disabilita un comando, `Transport` e'
|
|
946
|
+
* ritentabile, `Backend` no.
|
|
947
|
+
*
|
|
948
|
+
* Cosa questo client **non** fa, e non per dimenticanza: nessun `retry`, nessun `shareReplay`,
|
|
949
|
+
* nessuna cache, nessun debounce, nessuna intestazione propria. Traduce trasporto ed errori e
|
|
950
|
+
* nient'altro — la cache vive negli store, il debounce nel chiamante, i tentativi e
|
|
951
|
+
* l'autenticazione negli interceptor dell'ospite. E non tocca `definition.dialect` in nessun
|
|
952
|
+
* metodo (ADR 0009 e 0017): sarebbe una migrazione silenziosa delle espressioni SQL native.
|
|
953
|
+
*/
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* Configurazione del client. Iniettata e non cablata: in una libreria una costante non e' una
|
|
957
|
+
* scelta, e `const BASE = '/api/dpe'` in un file di libreria toglierebbe all'ospite la sua.
|
|
958
|
+
*/
|
|
959
|
+
interface DpeBuilderHttpConfig {
|
|
960
|
+
/** Prefisso comune degli endpoint, es. `/api/dpe` o `https://host/api/dpe`. Senza slash finale. */
|
|
961
|
+
baseUrl?: string;
|
|
962
|
+
/**
|
|
963
|
+
* Primitive opzionali che questo ambiente **non serve** (`contracts.md` §7, dichiarazione
|
|
964
|
+
* sottrattiva). E' l'unico modo che ha l'ospite di spegnere una primitiva che questo client
|
|
965
|
+
* implementa per forza: conoscendo tutti e dieci gli endpoint, li dichiarerebbe altrimenti tutti
|
|
966
|
+
* disponibili, e un comando attivo su un endpoint non servito fallisce alla pressione.
|
|
967
|
+
*/
|
|
968
|
+
unsupported?: readonly DpeOptionalPrimitive[];
|
|
969
|
+
}
|
|
970
|
+
declare const DPE_BUILDER_HTTP_CONFIG: InjectionToken<DpeBuilderHttpConfig>;
|
|
971
|
+
declare class HttpDpeBuilderApi extends DpeBuilderApi {
|
|
972
|
+
protected readonly http: HttpClient;
|
|
973
|
+
protected readonly config: DpeBuilderHttpConfig;
|
|
974
|
+
/**
|
|
975
|
+
* Deriva da `DpeBuilderHttpConfig.unsupported`: e' il ponte fra la configurazione e la regola
|
|
976
|
+
* di `contracts.md` §7. Non e' un doppione della configurazione — e' il campo che
|
|
977
|
+
* `core/dpe-capabilities.ts` legge, e leggerlo dal token li' significherebbe portare la
|
|
978
|
+
* configurazione HTTP dentro il calcolo delle capacita'.
|
|
979
|
+
*/
|
|
980
|
+
readonly unsupportedPrimitives: readonly DpeOptionalPrimitive[];
|
|
981
|
+
/**
|
|
982
|
+
* Composizione dell'URL. Sovrascriverlo basta a spostare tutte e dieci le rotte sotto un altro
|
|
983
|
+
* prefisso senza toccare un metodo.
|
|
984
|
+
*
|
|
985
|
+
* `?? ''` e non un default: `baseUrl: ''` e' una configurazione **valida** e significa «rotte
|
|
986
|
+
* relative alla radice», quindi non va rimpiazzata dal default del token. Il percorso porta
|
|
987
|
+
* sempre lo slash iniziale, cosi' non nasce un doppio slash.
|
|
988
|
+
*/
|
|
989
|
+
protected url(path: string): string;
|
|
990
|
+
/** Codifica di un segmento variabile. Un nome di definizione puo' contenere `/`, spazi, `&`. */
|
|
991
|
+
protected segment(value: string): string;
|
|
992
|
+
/**
|
|
993
|
+
* Cio' che avvolge **ogni** chiamata, e l'unico posto in cui si decide se una chiamata parte.
|
|
994
|
+
*
|
|
995
|
+
* `defer` non e' un vezzo: rende l'`Observable` **freddo** anche per il controllo delle
|
|
996
|
+
* primitive non servite, cosi' chi non sottoscrive non valuta nulla e chi si disiscrive annulla
|
|
997
|
+
* davvero la richiesta HTTP. E' la proprieta' per cui il contratto §7 e' `Observable` e non
|
|
998
|
+
* `Promise` — l'editor la usa per non accumulare validazioni in volo.
|
|
999
|
+
*
|
|
1000
|
+
* Il rigetto per primitiva non servita sta **fuori** dal `catchError`: passandogli dentro, un
|
|
1001
|
+
* `DpeApiError('MissingService')` verrebbe riclassificato `Transport` da `fail()`, che tratta
|
|
1002
|
+
* come guasto di rete tutto cio' che non e' una `HttpErrorResponse`.
|
|
1003
|
+
*/
|
|
1004
|
+
protected request<T>(primitive: DpeOptionalPrimitive | string, call: () => Observable<T>): Observable<T>;
|
|
1005
|
+
/** Vero se l'ospite ha dichiarato di non servire questa primitiva. */
|
|
1006
|
+
protected isUnsupported(primitive: string): boolean;
|
|
1007
|
+
/**
|
|
1008
|
+
* Rigetto di una primitiva dichiarata non servita, **senza toccare la rete**: sapere in anticipo
|
|
1009
|
+
* che un servizio non c'e' e chiederglielo comunque e' il difetto che `unsupportedPrimitives`
|
|
1010
|
+
* esiste per evitare, ed e' il motivo per cui il `501` -> `MissingService` non basta da solo.
|
|
1011
|
+
*/
|
|
1012
|
+
protected missing(primitive: string): Observable<never>;
|
|
1013
|
+
/**
|
|
1014
|
+
* `501 Not Implemented` diventa `MissingService`: e' cosi' che un ambiente incompleto degrada
|
|
1015
|
+
* **un comando** invece di rompere l'editor. Uno `0` (rete assente, CORS) e' `Transport`, come
|
|
1016
|
+
* qualunque errore che non sia una `HttpErrorResponse`; tutto il resto e' `Backend`.
|
|
1017
|
+
*
|
|
1018
|
+
* Il `404` resta deliberatamente `Backend` e non ha un ramo suo: qui non e' «primitiva assente»
|
|
1019
|
+
* ma «risorsa assente» — una definizione cancellata da altri, un nome che non esiste piu'. Chi
|
|
1020
|
+
* volesse distinguerlo lo mappi su una categoria propria, non su `MissingService`: disabilitare
|
|
1021
|
+
* un comando perche' un singolo nome non e' stato trovato sarebbe la reazione sbagliata.
|
|
1022
|
+
*
|
|
1023
|
+
* Il messaggio si prende in ordine — corpo dell'errore, messaggio della risposta, ripiego che
|
|
1024
|
+
* nomina la primitiva — e serve solo all'umano: l'editor guarda la categoria.
|
|
1025
|
+
*/
|
|
1026
|
+
protected fail(error: unknown, primitive: string): Observable<never>;
|
|
1027
|
+
protected httpGet<T>(path: string): Observable<T>;
|
|
1028
|
+
protected httpPost<T>(path: string, body: unknown): Observable<T>;
|
|
1029
|
+
protected httpPut<T>(path: string, body: unknown): Observable<T>;
|
|
1030
|
+
protected httpDelete<T>(path: string): Observable<T>;
|
|
1031
|
+
validate(definition: DpeDefinition): Observable<DpeValidateResult>;
|
|
1032
|
+
getTables(): Observable<TableSummary[]>;
|
|
1033
|
+
getTable(tableName: string): Observable<TableLookupResult>;
|
|
1034
|
+
/** L'**unica** rotta con involucro: il corpo porta anche i valori dei parametri (§7-bis). */
|
|
1035
|
+
compilePreview(definition: DpeDefinition, parameterValues?: DpeParameterValue[]): Observable<DpeCompileResult>;
|
|
1036
|
+
load(name: string): Observable<DpeDefinition>;
|
|
1037
|
+
save(definition: DpeDefinition): Observable<void>;
|
|
1038
|
+
/**
|
|
1039
|
+
* La dichiarazione dell'ambiente (ADR 0017). Questo client la implementa perche' conosce
|
|
1040
|
+
* l'endpoint, non perche' sappia se l'ospite lo serve — ed e' precisamente la ragione per cui
|
|
1041
|
+
* l'ADR 0020 ha aggiunto `unsupportedPrimitives`.
|
|
1042
|
+
*
|
|
1043
|
+
* Non e' un dettaglio: l'abilitazione della creazione nel catalogo (ADR 0019) dipende da questa
|
|
1044
|
+
* primitiva, quindi un ambiente che non la serve deve lasciare il comando disabilitato **con il
|
|
1045
|
+
* motivo**. Da qui i **tre** rami, che sono tre cose diverse e vanno tenute distinte:
|
|
1046
|
+
*
|
|
1047
|
+
* - **primitiva non implementata**: il metodo non viene sovrascritto, e il `MissingService` lo
|
|
1048
|
+
* produce l'identita' stessa del metodo. E' la strada di chi scrive la propria
|
|
1049
|
+
* implementazione di `DpeBuilderApi`, non di chi eredita questo client;
|
|
1050
|
+
* - **primitiva implementata ma non servita da questo ambiente**: e' il ramo centrale, quello
|
|
1051
|
+
* che questo file rende necessario. L'ospite mette `'getEnvironment'` in
|
|
1052
|
+
* `DpeBuilderHttpConfig.unsupported`, il comando resta disabilitato con il motivo, e **nessuna
|
|
1053
|
+
* richiesta parte**. Un metodo ereditato non si puo' dis-sovrascrivere: senza questa
|
|
1054
|
+
* dichiarazione il comando risulterebbe attivo;
|
|
1055
|
+
* - **primitiva servita che fallisce**: l'endpoint risponde male, e l'errore e' `Transport` o
|
|
1056
|
+
* `Backend`. Un ambiente rotto, non un ambiente incompleto.
|
|
1057
|
+
*
|
|
1058
|
+
* Rispondere `501` da questo endpoint per significare «non lo dichiaro» arriva allo stesso posto
|
|
1059
|
+
* nel modo sbagliato: costa un giro di rete a ogni apertura dell'editor per comunicare un fatto
|
|
1060
|
+
* che si conosce a tempo di configurazione.
|
|
1061
|
+
*
|
|
1062
|
+
* Cio' che l'editor fa della risposta resta suo: mostra il dialetto in sola lettura e segnala
|
|
1063
|
+
* senza correggere se differisce da quello della definizione.
|
|
1064
|
+
*/
|
|
1065
|
+
getEnvironment(): Observable<DpeEnvironment>;
|
|
1066
|
+
/** Nessun parametro di interrogazione: il filtro del catalogo e' locale, di proposito. */
|
|
1067
|
+
listDefinitions(): Observable<DpeDefinitionSummary[]>;
|
|
1068
|
+
/**
|
|
1069
|
+
* `POST` e non `PUT`: e' una **creazione**, quindi il backend puo' rifiutare un nome duplicato —
|
|
1070
|
+
* ed e' l'unica ragione per cui questa primitiva esiste separata da `save`. La risposta e' il
|
|
1071
|
+
* **sommario**, che chi crea deve adottare: il nome puo' essere stato normalizzato.
|
|
1072
|
+
*/
|
|
1073
|
+
createDefinition(definition: DpeDefinition): Observable<DpeDefinitionSummary>;
|
|
1074
|
+
deleteDefinition(name: string): Observable<void>;
|
|
1075
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HttpDpeBuilderApi, never>;
|
|
1076
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<HttpDpeBuilderApi>;
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Registra il client e la sua configurazione: l'integrazione in una riga che l'ADR 0020 chiedeva.
|
|
1080
|
+
*
|
|
1081
|
+
* **Non** chiama `provideHttpClient()`, e non e' una dimenticanza: il backend (`withFetch`), gli
|
|
1082
|
+
* interceptor, l'autenticazione e i cookie sono scelte dell'applicazione ospite, e una libreria
|
|
1083
|
+
* che le prende al posto suo la costringe a disfarle.
|
|
1084
|
+
*
|
|
1085
|
+
* `baseUrl` omesso ricade sul default, `baseUrl: ''` **no**: la stringa vuota e' una
|
|
1086
|
+
* configurazione valida («rotte relative alla radice») e un `||` la scambierebbe per assente.
|
|
1087
|
+
*/
|
|
1088
|
+
declare function provideDpeBuilderHttpApi(config?: DpeBuilderHttpConfig): EnvironmentProviders;
|
|
1089
|
+
|
|
1090
|
+
declare class DpeCatalogStore {
|
|
1091
|
+
private readonly api;
|
|
1092
|
+
private readonly destroyRef;
|
|
1093
|
+
/**
|
|
1094
|
+
* Le primitive disponibili, fotografate **alla costruzione** per identita' del metodo
|
|
1095
|
+
* (`dpe-capabilities.ts`). La disponibilita' si sa prima del clic: un comando che sembra attivo
|
|
1096
|
+
* e fallisce alla pressione insegna a non fidarsi dei bottoni.
|
|
1097
|
+
*/
|
|
1098
|
+
readonly capabilities: _esfaenza_dpe_builder.DpeCapabilities;
|
|
1099
|
+
/** Il comando di creazione dipende da **due** primitive, e il motivo va mostrato. */
|
|
1100
|
+
readonly createCommand: _esfaenza_dpe_builder.DpeCommandAvailability;
|
|
1101
|
+
private readonly _summaries;
|
|
1102
|
+
private readonly _isLoading;
|
|
1103
|
+
private readonly _isMutating;
|
|
1104
|
+
private readonly _error;
|
|
1105
|
+
private readonly _hasLoaded;
|
|
1106
|
+
private readonly _environmentDialect;
|
|
1107
|
+
/** Nell'ordine restituito dall'ospite, mai riordinato. */
|
|
1108
|
+
readonly summaries: _angular_core.Signal<readonly DpeDefinitionSummary[]>;
|
|
1109
|
+
/**
|
|
1110
|
+
* Due stati distinti e non uno: **elencare** e **scrivere** si vedono diversi. Un unico
|
|
1111
|
+
* "occupato" farebbe lampeggiare l'elenco a ogni cancellazione, e nasconderebbe il fatto che
|
|
1112
|
+
* dopo una scrittura l'elenco si ricarica.
|
|
1113
|
+
*/
|
|
1114
|
+
readonly isLoading: _angular_core.Signal<boolean>;
|
|
1115
|
+
readonly isMutating: _angular_core.Signal<boolean>;
|
|
1116
|
+
readonly error: _angular_core.Signal<DpeApiError | null>;
|
|
1117
|
+
/** Vero dopo la prima risposta: prima, un elenco vuoto non significa «nessuna definizione». */
|
|
1118
|
+
readonly hasLoaded: _angular_core.Signal<boolean>;
|
|
1119
|
+
/**
|
|
1120
|
+
* Il dialetto **dichiarato dall'ambiente** (ADR 0017), che e' quello con cui nasce una
|
|
1121
|
+
* definizione creata da qui. Non si chiede all'utente e non si sceglie per ripiego: senza
|
|
1122
|
+
* dichiarazione il comando di creazione resta spento (`createCommand`).
|
|
1123
|
+
*/
|
|
1124
|
+
readonly environmentDialect: _angular_core.Signal<SqlDialectKind | undefined>;
|
|
1125
|
+
readonly isEmpty: _angular_core.Signal<boolean>;
|
|
1126
|
+
constructor();
|
|
1127
|
+
/**
|
|
1128
|
+
* Ricarica l'elenco. Senza `listDefinitions` non e' un errore: e' un ambiente che non offre il
|
|
1129
|
+
* catalogo, e chi rende lo dice guardando `capabilities.listDefinitions`.
|
|
1130
|
+
*/
|
|
1131
|
+
refresh(): void;
|
|
1132
|
+
/**
|
|
1133
|
+
* Crea una definizione **subito**, non al primo salvataggio: `save` significa «scrivi questa
|
|
1134
|
+
* definizione» e non distingue inserimento da aggiornamento, quindi solo `createDefinition` da'
|
|
1135
|
+
* all'ospite il punto in cui rifiutare un nome duplicato. Una definizione che esiste solo nel
|
|
1136
|
+
* browser e' inoltre uno stato che l'elenco non puo' mostrare.
|
|
1137
|
+
*
|
|
1138
|
+
* Il dialetto arriva dall'ambiente e non dall'utente (ADR 0017): lo passa il chiamante, che lo
|
|
1139
|
+
* legge da `environmentDialect`.
|
|
1140
|
+
*
|
|
1141
|
+
* L'osservabile e' **freddo**: chi comanda si iscrive **una volta** e riceve il sommario che
|
|
1142
|
+
* l'ospite ha restituito — non quello costruito qui, perche' il nome puo' essere stato
|
|
1143
|
+
* normalizzato.
|
|
1144
|
+
*/
|
|
1145
|
+
create(name: string, label: string, dialect: SqlDialectKind): Observable<DpeDefinitionSummary>;
|
|
1146
|
+
/**
|
|
1147
|
+
* Duplica: `load` **e poi** `createDefinition`. Non esiste una primitiva di duplicazione sul
|
|
1148
|
+
* contratto, e non deve esistere — si comporrebbe di queste due comunque, e una primitiva
|
|
1149
|
+
* dedicata dovrebbe ridecidere lato host cosa cambia.
|
|
1150
|
+
*
|
|
1151
|
+
* Il dialetto e' quello della **definizione di partenza**, non quello dell'ambiente: le
|
|
1152
|
+
* espressioni sono SQL nativo (ADR 0006) e cambiare dialetto duplicando sarebbe una migrazione
|
|
1153
|
+
* silenziosa.
|
|
1154
|
+
*/
|
|
1155
|
+
duplicate(sourceName: string, name: string, label: string): Observable<DpeDefinitionSummary>;
|
|
1156
|
+
/** Cancella per nome e ricarica l'elenco. La conferma e' della schermata, non dello store. */
|
|
1157
|
+
remove(name: string): void;
|
|
1158
|
+
dismissError(): void;
|
|
1159
|
+
/**
|
|
1160
|
+
* Il tratto comune delle due scritture: stato di attesa, **`refresh` dopo il successo** — un
|
|
1161
|
+
* elenco che omette cio' che l'utente ha appena creato e' un elenco che mente — ed errore nel
|
|
1162
|
+
* signal invece che propagato. Chi comanda non deve trattare l'errore due volte.
|
|
1163
|
+
*/
|
|
1164
|
+
private mutate;
|
|
1165
|
+
/** Un errore del provider finisce in `error()` e **non lancia**: nessuno lo raccoglierebbe. */
|
|
1166
|
+
private fail;
|
|
1167
|
+
/** Cio' che l'host non categorizza diventa `Transport`, la categoria "riprovabile". */
|
|
1168
|
+
private toApiError;
|
|
1169
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeCatalogStore, never>;
|
|
1170
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DpeCatalogStore>;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
/**
|
|
1174
|
+
* Il grafo della definizione: **un solo posto** costruisce gli id di nodi, porte e archi, e
|
|
1175
|
+
* **un solo elenco** descrive dove vivono i riferimenti fra nodi.
|
|
1176
|
+
*
|
|
1177
|
+
* Perche' sta tutto qui. Un id di porta costruito in due modi diversi (canvas da un lato,
|
|
1178
|
+
* derivazione degli archi dall'altro) fa sparire un arco **senza nessun errore**: e' il
|
|
1179
|
+
* difetto piu' difficile da trovare in un editor a canvas. Allo stesso modo, un riferimento
|
|
1180
|
+
* dimenticato nell'elenco degli slot fa restare incoerente il documento dopo una rinomina,
|
|
1181
|
+
* anche lì in silenzio.
|
|
1182
|
+
*
|
|
1183
|
+
* Cosa **non** sta qui: nessuna regola di dominio. Questo file dice *dove* stanno i nomi dei
|
|
1184
|
+
* nodi a monte, non se un riferimento e' valido, se il grafo ha cicli (**I2**), se un nodo e'
|
|
1185
|
+
* a valle (**I3**) o quali colonne produca (**I4**). Quelle risposte arrivano da
|
|
1186
|
+
* `DpeBuilderApi.validate`.
|
|
1187
|
+
*/
|
|
1188
|
+
|
|
1189
|
+
declare function dpeNodeId(nodeName: string): string;
|
|
1190
|
+
/**
|
|
1191
|
+
* Porta di ingresso. Una porta **per slot** (e per indice, sugli slot a lista): un `JoinNode`
|
|
1192
|
+
* ha due ingressi distinti e attaccare l'arco alla porta sbagliata scambia primaria e
|
|
1193
|
+
* secondaria, che e' un join diverso.
|
|
1194
|
+
*/
|
|
1195
|
+
declare function dpeInputPortId(nodeName: string, slot: string, index?: number): string;
|
|
1196
|
+
/** Porta di uscita: una sola per nodo, lo schema prodotto e' uno. */
|
|
1197
|
+
declare function dpeOutputPortId(nodeName: string): string;
|
|
1198
|
+
/**
|
|
1199
|
+
* Id dell'arco: identifica la **destinazione** (nodo, slot, indice), non la coppia di nodi.
|
|
1200
|
+
* Due archi possono unire gli stessi due nodi su slot diversi — la primaria e la secondaria
|
|
1201
|
+
* di un self-join — e con un id per coppia uno dei due sparirebbe.
|
|
1202
|
+
*/
|
|
1203
|
+
declare function dpeEdgeId(targetNodeName: string, slot: string, index?: number): string;
|
|
1204
|
+
/**
|
|
1205
|
+
* Gli inversi. Stanno **accanto** ai costruttori e non nel canvas: la libreria di canvas
|
|
1206
|
+
* restituisce gli id nei suoi eventi, e chi li legge deve tornare al nome del nodo con la
|
|
1207
|
+
* stessa convenzione con cui li ha scritti. Separarli e' il modo con cui un giorno cambierebbe
|
|
1208
|
+
* uno solo dei due.
|
|
1209
|
+
*/
|
|
1210
|
+
declare function dpeParseNodeId(id: string): string | undefined;
|
|
1211
|
+
declare function dpeParseOutputPortId(id: string): string | undefined;
|
|
1212
|
+
declare function dpeParseInputPortId(id: string): {
|
|
1213
|
+
nodeName: string;
|
|
1214
|
+
slot: string;
|
|
1215
|
+
index?: number;
|
|
1216
|
+
} | undefined;
|
|
1217
|
+
/**
|
|
1218
|
+
* Uno slot e' un punto del nodo che contiene il nome di **un altro nodo**.
|
|
1219
|
+
*
|
|
1220
|
+
* `read` e `write` sono **posizionali e di lunghezza stabile**: `write(node, read(node))` non
|
|
1221
|
+
* cambia il nodo. E' la proprieta' che permette di implementare la rinomina come
|
|
1222
|
+
* `write(node, read(node).map(rinomina))` — cioe' con un solo cammino di codice, invece di
|
|
1223
|
+
* due elenchi (uno per leggere gli archi, uno per rinominare) che al primo campo aggiunto
|
|
1224
|
+
* diventano due elenchi diversi.
|
|
1225
|
+
*/
|
|
1226
|
+
interface DpeSourceSlot<TNode> {
|
|
1227
|
+
readonly slot: string;
|
|
1228
|
+
/**
|
|
1229
|
+
* `true` quando lo slot e' un **arco del DAG** (il flusso dei dati). `false` per i
|
|
1230
|
+
* riferimenti che sono altro: i `sourceName` dei `JoinResultField` ripetono le sorgenti del
|
|
1231
|
+
* join, e le relazioni di un gruppo atomico dichiarano una transazione dell'host, non un
|
|
1232
|
+
* flusso di dati (l'ordinamento dei sink e' esplicito e separato dal DAG).
|
|
1233
|
+
*/
|
|
1234
|
+
readonly isEdge: boolean;
|
|
1235
|
+
read(node: TNode): readonly (string | undefined)[];
|
|
1236
|
+
write(node: TNode, names: readonly (string | undefined)[]): TNode;
|
|
1237
|
+
}
|
|
1238
|
+
/** Gli slot di ogni collezione. Aggiungere un nodo significa aggiungere una riga qui. */
|
|
1239
|
+
declare const DPE_SOURCE_SLOTS: {
|
|
1240
|
+
readonly [K in DpeNodeCollectionName]: readonly DpeSourceSlot<DpeNodeCollectionMap[K]>[];
|
|
1241
|
+
};
|
|
1242
|
+
/** Un nodo con la collezione da cui viene: senza, non si sa quali slot leggere. */
|
|
1243
|
+
interface DpeLocatedNode<K extends DpeNodeCollectionName = DpeNodeCollectionName> {
|
|
1244
|
+
collection: K;
|
|
1245
|
+
index: number;
|
|
1246
|
+
node: DpeNodeCollectionMap[K];
|
|
1247
|
+
}
|
|
1248
|
+
/** Tutti i nodi, nell'ordine delle collezioni (sorgenti -> trasformazioni -> sink). */
|
|
1249
|
+
declare function dpeAllNodes(definition: DpeDefinition): DpeLocatedNode[];
|
|
1250
|
+
declare function dpeFindNode(definition: DpeDefinition, nodeName: string): DpeLocatedNode | undefined;
|
|
1251
|
+
interface DpeSourceReference {
|
|
1252
|
+
/** Nodo che contiene il riferimento (la destinazione dell'arco). */
|
|
1253
|
+
targetNodeName: string;
|
|
1254
|
+
collection: DpeNodeCollectionName;
|
|
1255
|
+
slot: string;
|
|
1256
|
+
/** Presente solo sugli slot a lista. */
|
|
1257
|
+
index?: number;
|
|
1258
|
+
isEdge: boolean;
|
|
1259
|
+
/** Nome riferito; assente quando lo slot e' vuoto (nodo non collegato). */
|
|
1260
|
+
sourceName?: string;
|
|
1261
|
+
}
|
|
1262
|
+
/** I riferimenti di un singolo nodo, in ordine di slot. */
|
|
1263
|
+
declare function dpeNodeSourceReferences(located: DpeLocatedNode): DpeSourceReference[];
|
|
1264
|
+
interface DpeGraphNode {
|
|
1265
|
+
id: string;
|
|
1266
|
+
name: string;
|
|
1267
|
+
collection: DpeNodeCollectionName;
|
|
1268
|
+
outputPortId: string;
|
|
1269
|
+
}
|
|
1270
|
+
interface DpeGraphEdge {
|
|
1271
|
+
id: string;
|
|
1272
|
+
/** Nome del nodo a monte, come scritto nel documento. */
|
|
1273
|
+
fromNodeName: string;
|
|
1274
|
+
toNodeName: string;
|
|
1275
|
+
slot: string;
|
|
1276
|
+
index?: number;
|
|
1277
|
+
fromPortId: string;
|
|
1278
|
+
toPortId: string;
|
|
1279
|
+
/**
|
|
1280
|
+
* `false` quando il nome a monte non corrisponde a nessun nodo della definizione. L'arco
|
|
1281
|
+
* **si mostra comunque**: la topologia mostrata e' quella reale, e un riferimento rotto va
|
|
1282
|
+
* visto, non nascosto. La diagnostica che lo qualifica (`DPE_REF_UNKNOWN_NODE`) arriva dal
|
|
1283
|
+
* backend.
|
|
1284
|
+
*/
|
|
1285
|
+
isResolved: boolean;
|
|
1286
|
+
}
|
|
1287
|
+
interface DpeGraph {
|
|
1288
|
+
nodes: DpeGraphNode[];
|
|
1289
|
+
edges: DpeGraphEdge[];
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Deriva nodi e archi dalla definizione, per riferimento di nome. Funzione pura: nessuna
|
|
1293
|
+
* lettura di stato, nessuna dipendenza da Angular, testabile senza DOM.
|
|
1294
|
+
*/
|
|
1295
|
+
declare function dpeBuildGraph(definition: DpeDefinition): DpeGraph;
|
|
1296
|
+
/** Le porte di ingresso di un nodo, nell'ordine in cui vanno disegnate. */
|
|
1297
|
+
interface DpeInputPort {
|
|
1298
|
+
id: string;
|
|
1299
|
+
slot: string;
|
|
1300
|
+
index?: number;
|
|
1301
|
+
/** Nome collegato, assente se la porta e' libera. */
|
|
1302
|
+
sourceName?: string;
|
|
1303
|
+
}
|
|
1304
|
+
declare function dpeInputPorts(located: DpeLocatedNode): DpeInputPort[];
|
|
1305
|
+
/**
|
|
1306
|
+
* Riscrive un riferimento in **uno** slot di **un** nodo. E' il mattone di `connect` e
|
|
1307
|
+
* `disconnect` dello store: passando `undefined` la porta torna libera.
|
|
1308
|
+
*/
|
|
1309
|
+
declare function dpeWriteSourceReference<K extends DpeNodeCollectionName>(collection: K, node: DpeNodeCollectionMap[K], slotName: string, index: number | undefined, sourceName: string | undefined): DpeNodeCollectionMap[K];
|
|
1310
|
+
/**
|
|
1311
|
+
* **Rinominare un nodo e' un refactoring globale, non locale** (**I5**).
|
|
1312
|
+
*
|
|
1313
|
+
* Questa e' l'unica funzione che rinomina: aggiorna il `name` del nodo e **ogni** riferimento
|
|
1314
|
+
* a valle, passando dall'unico elenco di slot — `sourceName`, `sources`,
|
|
1315
|
+
* `primarySourceName`/`secondarySourceName`, i `sourceName` dei `JoinResultField` e i nomi
|
|
1316
|
+
* dentro i gruppi atomici. Se una collezione di riferimenti sfuggisse, il documento
|
|
1317
|
+
* diventerebbe silenziosamente incoerente: e' il difetto che questa funzione esiste per non
|
|
1318
|
+
* avere.
|
|
1319
|
+
*
|
|
1320
|
+
* Cosa **non** fa, di proposito: non rinomina gli **alias di colonna** (sono un altro spazio
|
|
1321
|
+
* di nomi) e non decide se il nuovo nome sia lecito o già usato — l'unicita' e' **I1**, la
|
|
1322
|
+
* verifica il backend.
|
|
1323
|
+
*
|
|
1324
|
+
* Il confronto e' **esatto**, non case-insensitive: `domain-model.md` dichiara il confronto
|
|
1325
|
+
* `OrdinalIgnoreCase` per gli **alias di colonna** e non dice nulla sui nomi dei nodi.
|
|
1326
|
+
* Rinominare anche le occorrenze con capitalizzazione diversa significherebbe, se il backend
|
|
1327
|
+
* risolvesse i nomi in modo esatto, riscrivere il riferimento a un nodo **diverso**.
|
|
1328
|
+
*/
|
|
1329
|
+
declare function dpeRenameNode(definition: DpeDefinition, oldName: string, newName: string): DpeDefinition;
|
|
1330
|
+
/** Quante occorrenze toccherebbe una rinomina: serve a dirlo prima, non dopo. */
|
|
1331
|
+
declare function dpeCountReferences(definition: DpeDefinition, nodeName: string): number;
|
|
1332
|
+
|
|
1333
|
+
/**
|
|
1334
|
+
* Utility pure sulle diagnostiche **ricevute** dal backend: raggruppamento per nodo, gravita'
|
|
1335
|
+
* peggiore, e la distinzione fra "da correggere" e "non ancora compilabile".
|
|
1336
|
+
*
|
|
1337
|
+
* Qui non nasce nessuna diagnostica e non si giudica nessuna definizione: si legge cio' che il
|
|
1338
|
+
* backend ha detto e si decide **come renderlo**. La sola informazione interpretata e' il
|
|
1339
|
+
* `DiagnosticPath`, che il contratto pubblica in **due forme** (con nome del nodo dalla
|
|
1340
|
+
* validazione, con solo indice dalla deserializzazione): chi legge deve accettarle entrambe,
|
|
1341
|
+
* altrimenti le diagnostiche del caricamento di un file non sono navigabili.
|
|
1342
|
+
*/
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* Il nodo a cui una diagnostica si riferisce, se ricavabile.
|
|
1346
|
+
*
|
|
1347
|
+
* Tre strade, nell'ordine: il nome nel primo segmento del percorso; l'argomento canonico
|
|
1348
|
+
* `node`; l'indice del primo segmento risolto nella collezione corrispondente della
|
|
1349
|
+
* definizione — che e' il caso della deserializzazione, dove i nomi non sono ancora noti.
|
|
1350
|
+
* Senza la terza, un `filters[0].sourceName` resterebbe una riga non cliccabile.
|
|
1351
|
+
*/
|
|
1352
|
+
declare function dpeDiagnosticNodeName(diagnostic: Diagnostic, definition?: DpeDefinition): string | undefined;
|
|
1353
|
+
/** Il campo in causa, per evidenziarlo nell'ispettore. */
|
|
1354
|
+
declare function dpeDiagnosticField(diagnostic: Diagnostic): string | undefined;
|
|
1355
|
+
/**
|
|
1356
|
+
* `true` per l'unico codice che significa "hai fatto bene, siamo noi" (**I10**, ADR 0005):
|
|
1357
|
+
* `Forecast`, `CustomNode`, costrutto non supportato dal dialetto scelto. Non va mescolato
|
|
1358
|
+
* con i `DPE_MODEL_*`, che l'utente deve correggere.
|
|
1359
|
+
*/
|
|
1360
|
+
declare function dpeIsNotCompilable(diagnostic: Diagnostic): boolean;
|
|
1361
|
+
/**
|
|
1362
|
+
* `true` quando la diagnostica riguarda le **capacita' del dialetto** e non la definizione in
|
|
1363
|
+
* se': l'interfaccia deve dire «questo dialetto non lo supporta», perche' lo stesso documento
|
|
1364
|
+
* su un altro dialetto sarebbe compilabile.
|
|
1365
|
+
*/
|
|
1366
|
+
declare function dpeIsDialectDiagnostic(diagnostic: Diagnostic): boolean;
|
|
1367
|
+
interface DpeNodeDiagnostics {
|
|
1368
|
+
/** Diagnostiche ancorate al nodo, nell'ordine ricevuto (**I6**: l'elenco e' esaustivo). */
|
|
1369
|
+
diagnostics: Diagnostic[];
|
|
1370
|
+
/** La gravita' peggiore fra quelle presenti. */
|
|
1371
|
+
severity?: DiagnosticSeverity;
|
|
1372
|
+
/**
|
|
1373
|
+
* Il nodo e' **valido ma non compilabile**: stato distinto da "non valido", e l'unico per
|
|
1374
|
+
* cui la UI non deve chiedere all'utente di correggere niente.
|
|
1375
|
+
*/
|
|
1376
|
+
isNotCompilable: boolean;
|
|
1377
|
+
}
|
|
1378
|
+
declare function dpeWorstSeverity(diagnostics: readonly Diagnostic[]): DiagnosticSeverity | undefined;
|
|
1379
|
+
/** Raggruppa per nodo. Le diagnostiche non ancorabili a un nodo non si perdono: vedi sotto. */
|
|
1380
|
+
declare function dpeGroupDiagnosticsByNode(diagnostics: readonly Diagnostic[], definition?: DpeDefinition): Map<string, DpeNodeDiagnostics>;
|
|
1381
|
+
/**
|
|
1382
|
+
* Le diagnostiche che **non** appartengono a nessun nodo (radice, parametri, sequenza dei
|
|
1383
|
+
* writeback, grafo intero). Esistono come funzione a se' perche' il pannello deve mostrarle:
|
|
1384
|
+
* un `DPE_GRAPH_NO_WRITEBACK` che scompare perche' non ha un nodo a cui attaccarsi sarebbe la
|
|
1385
|
+
* diagnostica piu' importante di tutte a non arrivare all'utente.
|
|
1386
|
+
*/
|
|
1387
|
+
declare function dpeDefinitionLevelDiagnostics(diagnostics: readonly Diagnostic[], definition?: DpeDefinition): Diagnostic[];
|
|
1388
|
+
/** Testo leggibile del percorso, per la riga del pannello. */
|
|
1389
|
+
declare function dpeDiagnosticLocationLabel(diagnostic: Diagnostic, definition?: DpeDefinition): string;
|
|
1390
|
+
/** I nomi dei nodi presenti nella definizione: serve a chi naviga dal pannello al canvas. */
|
|
1391
|
+
declare function dpeKnownNodeNames(definition: DpeDefinition): Set<string>;
|
|
1392
|
+
|
|
1393
|
+
/**
|
|
1394
|
+
* Le coordinate di un nodo sul canvas — ADR 0013.
|
|
1395
|
+
*
|
|
1396
|
+
* Vivono in `extensionData` sotto la chiave namespaced `dpe:layout`, forma `{x, y}`. Il
|
|
1397
|
+
* backend le conserva senza interpretarle (**I7**), la validazione non le guarda, il
|
|
1398
|
+
* compilatore non le vede: l'unico livello che gli da' significato e' l'editor.
|
|
1399
|
+
*
|
|
1400
|
+
* Due regole dell'ADR sono implementate qui, e sono le sole che contano:
|
|
1401
|
+
*
|
|
1402
|
+
* - le coordinate sono **opzionali**: una definizione scritta a mano non le ha e resta
|
|
1403
|
+
* valida; in loro assenza si esegue dagre;
|
|
1404
|
+
* - un `dpe:layout` **malformato o parziale si ignora**. Un documento arrivato da un'altra
|
|
1405
|
+
* versione non deve poter rompere il canvas, e "meta' coordinata" non e' una posizione:
|
|
1406
|
+
* accettarla metterebbe il nodo a `x` giusta e `y` zero, cioe' in un posto che nessuno ha
|
|
1407
|
+
* scelto.
|
|
1408
|
+
*/
|
|
1409
|
+
|
|
1410
|
+
/** La chiave e' namespaced perche' `extensionData` e' anche dove atterrano i campi futuri. */
|
|
1411
|
+
declare const DPE_LAYOUT_KEY = "dpe:layout";
|
|
1412
|
+
interface DpeNodePosition {
|
|
1413
|
+
x: number;
|
|
1414
|
+
y: number;
|
|
1415
|
+
}
|
|
1416
|
+
/** Legge la posizione, oppure `undefined` se assente o non utilizzabile. */
|
|
1417
|
+
declare function dpeReadNodePosition(node: DpeAnyNode): DpeNodePosition | undefined;
|
|
1418
|
+
/** Scrive la posizione producendo un nuovo nodo: il documento resta immutabile. */
|
|
1419
|
+
declare function dpeWriteNodePosition<TNode extends DpeAnyNode>(node: TNode, position: DpeNodePosition): TNode;
|
|
1420
|
+
/** Vero quando **tutti** i nodi hanno una posizione: se no, il canvas rifa' il layout. */
|
|
1421
|
+
declare function dpeHasCompleteLayout(nodes: readonly DpeAnyNode[]): boolean;
|
|
1422
|
+
|
|
1423
|
+
/** Una definizione vuota ma **leggibile**: `formatVersion` e `dialect` non sono opzionali. */
|
|
1424
|
+
declare function dpeEmptyDefinition(name: string, label: string, dialect: SqlDialectKind): DpeDefinition;
|
|
1425
|
+
declare class DpeDocumentStore {
|
|
1426
|
+
private readonly _definition;
|
|
1427
|
+
private readonly _validateResult;
|
|
1428
|
+
private readonly _compileResult;
|
|
1429
|
+
/**
|
|
1430
|
+
* I nodi selezionati, in ordine di gesto. E' una **lista** e non un nome singolo perche' il
|
|
1431
|
+
* canvas sa selezionare piu' nodi (riquadro, `Ctrl+A`) e trascinarli insieme: tenere qui un solo
|
|
1432
|
+
* nome costringerebbe la libreria a conservare gli altri, cioe' a essere di nuovo autorevole
|
|
1433
|
+
* sulla selezione.
|
|
1434
|
+
*/
|
|
1435
|
+
private readonly _selectedNodeNames;
|
|
1436
|
+
private readonly _past;
|
|
1437
|
+
private readonly _future;
|
|
1438
|
+
/**
|
|
1439
|
+
* Istantanea di riferimento: l'ultimo stato **salvato**. Non e' un contatore di operazioni.
|
|
1440
|
+
* Contare le mutazioni sembra equivalente e non lo e': dopo un `undo` il contatore sale, cioe'
|
|
1441
|
+
* dichiara piu' modifiche di prima proprio quando l'utente ne ha disfatta una. Serve a decidere
|
|
1442
|
+
* se salvare, quindi deve rispondere alla domanda giusta — "differisce da cio' che e' salvato?"
|
|
1443
|
+
* — e tornare a "no" quando si annulla fino allo stato di partenza.
|
|
1444
|
+
*/
|
|
1445
|
+
private readonly _savedSnapshot;
|
|
1446
|
+
/** La definizione corrente: unica fonte di verita' per canvas, ispettori e pannelli. */
|
|
1447
|
+
readonly definition: _angular_core.Signal<DpeDefinition>;
|
|
1448
|
+
/** Nodi e archi derivati dalla definizione. Ricalcolati solo quando la definizione cambia. */
|
|
1449
|
+
readonly graph: _angular_core.Signal<DpeGraph>;
|
|
1450
|
+
readonly selectedNodeNames: _angular_core.Signal<readonly string[]>;
|
|
1451
|
+
/** Insieme dei selezionati: il canvas lo interroga una volta per nodo a ogni render. */
|
|
1452
|
+
readonly selectedNodeNameSet: _angular_core.Signal<ReadonlySet<string>>;
|
|
1453
|
+
/**
|
|
1454
|
+
* Il nodo che l'ispettore mostra: il **primo** della selezione. Un ispettore per piu' nodi
|
|
1455
|
+
* insieme mostrerebbe campi che appartengono a nodi diversi, che e' peggio di non mostrarne.
|
|
1456
|
+
*/
|
|
1457
|
+
readonly selectedNodeName: _angular_core.Signal<string | undefined>;
|
|
1458
|
+
readonly selectedNode: _angular_core.Signal<DpeAnyNode | undefined>;
|
|
1459
|
+
readonly validateResult: _angular_core.Signal<DpeValidateResult | undefined>;
|
|
1460
|
+
readonly compileResult: _angular_core.Signal<DpeCompileResult | undefined>;
|
|
1461
|
+
readonly diagnostics: _angular_core.Signal<readonly Diagnostic[]>;
|
|
1462
|
+
readonly schemas: _angular_core.Signal<readonly DpeNodeSchemaInfo[]>;
|
|
1463
|
+
readonly executionOrder: _angular_core.Signal<readonly string[]>;
|
|
1464
|
+
readonly writebackSequence: _angular_core.Signal<readonly DpeWritebackStep[]>;
|
|
1465
|
+
/** Schema per nome di nodo: la vista dello schema lo cerca per nodo, non per posizione. */
|
|
1466
|
+
readonly schemaByNode: _angular_core.Signal<ReadonlyMap<string, DpeNodeSchemaInfo>>;
|
|
1467
|
+
/**
|
|
1468
|
+
* Diagnostiche raggruppate per nodo, piu' quelle che **non** appartengono a nessun nodo
|
|
1469
|
+
* (radice, parametri, grafo intero): tenerle separate e' l'unico modo perche' un
|
|
1470
|
+
* `DPE_GRAPH_NO_WRITEBACK` non scompaia solo perche' non ha un nodo a cui attaccarsi.
|
|
1471
|
+
*/
|
|
1472
|
+
readonly diagnosticsByNode: _angular_core.Signal<ReadonlyMap<string, DpeNodeDiagnostics>>;
|
|
1473
|
+
readonly definitionDiagnostics: _angular_core.Signal<readonly Diagnostic[]>;
|
|
1474
|
+
/** Posizioni lette da `dpe:layout` (ADR 0013): assenti dove il documento non le porta. */
|
|
1475
|
+
readonly positions: _angular_core.Signal<ReadonlyMap<string, DpeNodePosition>>;
|
|
1476
|
+
readonly canUndo: _angular_core.Signal<boolean>;
|
|
1477
|
+
readonly canRedo: _angular_core.Signal<boolean>;
|
|
1478
|
+
/**
|
|
1479
|
+
* Vero quando il documento differisce dall'ultimo salvataggio. Il confronto e' fra istantanee
|
|
1480
|
+
* JSON — la stessa moneta dell'undo/redo — e **non** un conteggio di differenze: un elenco di
|
|
1481
|
+
* differenze costa quanto un diff strutturale, e nessuno lo legge come numero.
|
|
1482
|
+
*
|
|
1483
|
+
* Confronto testuale, quindi sensibile all'ordine delle chiavi. Le mutazioni producono nuovi
|
|
1484
|
+
* valori per spread, che l'ordine lo conserva, e l'undo riparte dalla stessa serializzazione:
|
|
1485
|
+
* l'unico esito possibile di una divergenza d'ordine sarebbe un falso "modificata", cioe' un
|
|
1486
|
+
* salvataggio in piu' e mai una perdita.
|
|
1487
|
+
*/
|
|
1488
|
+
readonly isDirty: _angular_core.Signal<boolean>;
|
|
1489
|
+
/**
|
|
1490
|
+
* Sostituisce la definizione. Azzera la cronologia: le istantanee della definizione
|
|
1491
|
+
* precedente non sono passi di quella nuova, e un undo che riportasse a un altro documento
|
|
1492
|
+
* sarebbe una perdita di dati che l'utente non ha chiesto.
|
|
1493
|
+
*/
|
|
1494
|
+
load(definition: DpeDefinition): void;
|
|
1495
|
+
/** Deposita il risultato della validazione. Nessuna interpretazione: si mostra cio' che c'e'. */
|
|
1496
|
+
applyValidateResult(result: DpeValidateResult | undefined): void;
|
|
1497
|
+
applyCompileResult(result: DpeCompileResult | undefined): void;
|
|
1498
|
+
/**
|
|
1499
|
+
* L'ospite ha salvato: da qui in poi il riferimento e' il documento **effettivamente
|
|
1500
|
+
* persistito**, che si passa come argomento.
|
|
1501
|
+
*
|
|
1502
|
+
* Il parametro non e' un vezzo: un salvataggio e' asincrono, e nel frattempo l'utente puo'
|
|
1503
|
+
* avere continuato a scrivere. Fissando il riferimento sullo stato *corrente* si dichiarerebbe
|
|
1504
|
+
* salvato anche cio' che e' stato scritto dopo l'invio, cioe' esattamente il lavoro che si
|
|
1505
|
+
* perderebbe. Omesso, vale lo stato corrente: e' il caso di chi salva in modo sincrono.
|
|
1506
|
+
*/
|
|
1507
|
+
markSaved(saved?: DpeDefinition): void;
|
|
1508
|
+
/**
|
|
1509
|
+
* **L'unico** punto che decide quale nodo e' selezionato. La selezione ha una sola fonte di
|
|
1510
|
+
* verita', come la definizione: la classe nel DOM e lo stato di selezione della libreria di
|
|
1511
|
+
* canvas ne **derivano**, non la stabiliscono. Due scritture indipendenti sullo stesso fatto
|
|
1512
|
+
* producono due nodi selezionati insieme e un utente che non sa su cosa sta agendo.
|
|
1513
|
+
*/
|
|
1514
|
+
select(nodeName: string | undefined): void;
|
|
1515
|
+
/** Selezione multipla (riquadro, `Ctrl+A`): la lista che arriva dal gesto, senza duplicati. */
|
|
1516
|
+
selectMany(nodeNames: readonly string[]): void;
|
|
1517
|
+
/** Proprieta' della radice: etichetta, descrizione, dialetto, parametri. */
|
|
1518
|
+
patchDefinition(patch: Partial<DpeDefinition>): void;
|
|
1519
|
+
addNode<K extends DpeNodeCollectionName>(collection: K, node: DpeNodeCollectionMap[K]): void;
|
|
1520
|
+
updateNode<K extends DpeNodeCollectionName>(collection: K, nodeName: string, patch: Partial<DpeNodeCollectionMap[K]>): void;
|
|
1521
|
+
/**
|
|
1522
|
+
* Rimuove un nodo. I riferimenti a valle **restano** e diventano riferimenti rotti: e' cio'
|
|
1523
|
+
* che il documento dice davvero, e il backend li segnala (`DPE_REF_UNKNOWN_NODE`). Pulirli
|
|
1524
|
+
* qui vorrebbe dire decidere al posto dell'utente che quel filtro non serve piu'.
|
|
1525
|
+
*/
|
|
1526
|
+
removeNode(nodeName: string): void;
|
|
1527
|
+
/**
|
|
1528
|
+
* L'**unico** punto che rinomina un nodo (**I5**): delega alla funzione pura, che aggiorna
|
|
1529
|
+
* ogni riferimento a valle passando dall'unico elenco di slot.
|
|
1530
|
+
*/
|
|
1531
|
+
renameNode(oldName: string, newName: string): void;
|
|
1532
|
+
/** Quante occorrenze toccherebbe una rinomina: si dice prima, non dopo. */
|
|
1533
|
+
countReferences(nodeName: string): number;
|
|
1534
|
+
/**
|
|
1535
|
+
* Crea un nodo della categoria data nella posizione indicata e restituisce il nome
|
|
1536
|
+
* assegnato, cosi' chi lo ha creato puo' selezionarlo subito.
|
|
1537
|
+
*/
|
|
1538
|
+
createNodeAt<K extends DpeNodeCollectionName>(collection: K, position: DpeNodePosition): string;
|
|
1539
|
+
/**
|
|
1540
|
+
* Sposta un nodo scrivendo `dpe:layout`. `silent` non aggiunge un passo di cronologia:
|
|
1541
|
+
* trascinare cinque nodi insieme e' **un** gesto, e cinque passi di undo per un solo
|
|
1542
|
+
* trascinamento sono cinque passi che l'utente non ha fatto.
|
|
1543
|
+
*/
|
|
1544
|
+
moveNode(nodeName: string, position: DpeNodePosition, options?: {
|
|
1545
|
+
silent?: boolean;
|
|
1546
|
+
}): void;
|
|
1547
|
+
/**
|
|
1548
|
+
* Applica un layout calcolato **su comando dell'utente** («Riordina»): un passo di cronologia
|
|
1549
|
+
* per l'intero riordino, e il documento risulta modificato, perche' lo e'.
|
|
1550
|
+
*/
|
|
1551
|
+
applyPositions(positions: ReadonlyMap<string, DpeNodePosition>): void;
|
|
1552
|
+
/**
|
|
1553
|
+
* Layout **iniziale** di un documento che non porta coordinate (ADR 0013: sono opzionali).
|
|
1554
|
+
*
|
|
1555
|
+
* Non e' una modifica dell'utente: non entra nella cronologia e **ri-fissa l'istantanea di
|
|
1556
|
+
* riferimento**, cosi' aprire un documento non produce «modificata». Un indicatore che dice
|
|
1557
|
+
* «modificata» appena si apre insegna a ignorarlo, e un indicatore ignorato e' peggio di
|
|
1558
|
+
* nessun indicatore. Il prezzo accettato: chi chiude senza salvare perde le coordinate
|
|
1559
|
+
* calcolate, che dagre rigenera in modo deterministico.
|
|
1560
|
+
*
|
|
1561
|
+
* Il riferimento si sposta **solo** se il documento non era gia' modificato: se l'utente ha
|
|
1562
|
+
* scritto qualcosa, un layout non puo' dichiarare salvato il suo lavoro.
|
|
1563
|
+
*/
|
|
1564
|
+
applyInitialPositions(positions: ReadonlyMap<string, DpeNodePosition>): void;
|
|
1565
|
+
/**
|
|
1566
|
+
* Collega una porta di ingresso di `targetNodeName` al nodo `sourceName`. Non verifica che
|
|
1567
|
+
* il collegamento sia lecito: cicli (**I2**) e riferimenti a valle (**I3**) li rifiuta il
|
|
1568
|
+
* backend, e l'errore compare subito perche' la validazione parte dopo la mutazione.
|
|
1569
|
+
*/
|
|
1570
|
+
connect(targetNodeName: string, slot: string, sourceName: string, index?: number): void;
|
|
1571
|
+
/** Scollega una porta: lo slot torna vuoto, non a stringa vuota. */
|
|
1572
|
+
disconnect(targetNodeName: string, slot: string, index?: number): void;
|
|
1573
|
+
undo(): void;
|
|
1574
|
+
redo(): void;
|
|
1575
|
+
private writeReference;
|
|
1576
|
+
/** Scrive le posizioni su tutte le collezioni producendo una nuova definizione. */
|
|
1577
|
+
private withPositions;
|
|
1578
|
+
/**
|
|
1579
|
+
* Sostituisce una collezione producendo una nuova definizione. Il cast e' confinato qui:
|
|
1580
|
+
* TypeScript non correla la chiave di collezione con il tipo di nodo dentro un accesso
|
|
1581
|
+
* dinamico, e la mappa dei tipi serve ai chiamanti, non a questa riga.
|
|
1582
|
+
*/
|
|
1583
|
+
private withCollection;
|
|
1584
|
+
private commit;
|
|
1585
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeDocumentStore, never>;
|
|
1586
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DpeDocumentStore>;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
interface DpeLayoutNodeInput {
|
|
1590
|
+
name: string;
|
|
1591
|
+
width: number;
|
|
1592
|
+
height: number;
|
|
1593
|
+
}
|
|
1594
|
+
interface DpeLayoutEdgeInput {
|
|
1595
|
+
/** Nome del nodo a monte. */
|
|
1596
|
+
from: string;
|
|
1597
|
+
/** Nome del nodo a valle. */
|
|
1598
|
+
to: string;
|
|
1599
|
+
/** Identificatore dell'arco: dagre ne ha bisogno per ammettere archi paralleli. */
|
|
1600
|
+
id: string;
|
|
1601
|
+
}
|
|
1602
|
+
interface DpeLayoutPosition {
|
|
1603
|
+
x: number;
|
|
1604
|
+
y: number;
|
|
1605
|
+
}
|
|
1606
|
+
type DpeLayoutDirection = 'TB' | 'LR';
|
|
1607
|
+
interface DpeLayoutOptions {
|
|
1608
|
+
/** Default `TB`: i dati scendono dalle sorgenti ai sink. */
|
|
1609
|
+
direction?: DpeLayoutDirection;
|
|
1610
|
+
/** Distanza fra i livelli. */
|
|
1611
|
+
rankSeparation?: number;
|
|
1612
|
+
/** Distanza fra i nodi dello stesso livello. */
|
|
1613
|
+
nodeSeparation?: number;
|
|
1614
|
+
/** Angolo in alto a sinistra del grafo risultante. */
|
|
1615
|
+
origin?: DpeLayoutPosition;
|
|
1616
|
+
}
|
|
1617
|
+
declare class DpeLayoutService {
|
|
1618
|
+
/**
|
|
1619
|
+
* Calcola le posizioni. La chiave della mappa e' il **nome** del nodo, non il suo id sul
|
|
1620
|
+
* canvas: il nome e' cio' che identifica un nodo nel documento, e passare dall'id
|
|
1621
|
+
* costringerebbe questo servizio a conoscere la costruzione degli id.
|
|
1622
|
+
*/
|
|
1623
|
+
layout(nodes: readonly DpeLayoutNodeInput[], edges: readonly DpeLayoutEdgeInput[], options?: DpeLayoutOptions): Map<string, DpeLayoutPosition>;
|
|
1624
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeLayoutService, never>;
|
|
1625
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DpeLayoutService>;
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
interface DpeTableState {
|
|
1629
|
+
outcome: TableLookupOutcome;
|
|
1630
|
+
table?: TableDescriptor;
|
|
1631
|
+
}
|
|
1632
|
+
declare class DpeMetadataStore {
|
|
1633
|
+
private readonly api;
|
|
1634
|
+
private readonly _tables;
|
|
1635
|
+
private readonly _isLoadingTables;
|
|
1636
|
+
private readonly _tablesRequested;
|
|
1637
|
+
private readonly _byName;
|
|
1638
|
+
private readonly pending;
|
|
1639
|
+
readonly tables: _angular_core.Signal<readonly TableSummary[]>;
|
|
1640
|
+
readonly isLoadingTables: _angular_core.Signal<boolean>;
|
|
1641
|
+
/** Idempotente: la prima chiamata carica, le successive non fanno nulla. */
|
|
1642
|
+
loadTables(): void;
|
|
1643
|
+
/** Stato noto di una tabella, se già richiesta. */
|
|
1644
|
+
stateOf(tableName: string): DpeTableState | undefined;
|
|
1645
|
+
/** Chiede la descrizione di una tabella una sola volta per nome. */
|
|
1646
|
+
describe(tableName: string): void;
|
|
1647
|
+
private put;
|
|
1648
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeMetadataStore, never>;
|
|
1649
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DpeMetadataStore>;
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
/**
|
|
1653
|
+
* Catalogo delle categorie di nodo: etichetta italiana, collezione JSON di appartenenza,
|
|
1654
|
+
* numero di sorgenti ammesse.
|
|
1655
|
+
*
|
|
1656
|
+
* **Descrittivo, non normativo.** Serve alla palette e alle etichette dell'interfaccia. Non
|
|
1657
|
+
* e' validazione: che un `AppendNode` con una sola sorgente sia sbagliato lo dice il backend,
|
|
1658
|
+
* non questo file, e i due non devono mai diventare due fonti di verita' in disaccordo. I
|
|
1659
|
+
* conteggi qui sotto servono a decidere **quante porte disegnare**, che e' una domanda di
|
|
1660
|
+
* rendering.
|
|
1661
|
+
*/
|
|
1662
|
+
|
|
1663
|
+
interface DpeNodeCategory {
|
|
1664
|
+
/** Collezione JSON della radice: e' anche la chiave con cui si legge il documento. */
|
|
1665
|
+
collection: DpeNodeCollectionName;
|
|
1666
|
+
/** Etichetta breve, per la palette e per l'intestazione della card sul canvas. */
|
|
1667
|
+
label: string;
|
|
1668
|
+
/** Una riga di spiegazione, per il tooltip della palette. */
|
|
1669
|
+
description: string;
|
|
1670
|
+
/** Numero minimo di sorgenti che il nodo dichiara (0 per i punti d'ingresso). */
|
|
1671
|
+
minSources: number;
|
|
1672
|
+
/** Numero massimo, `undefined` = illimitato (`Append`, `CustomNode`). */
|
|
1673
|
+
maxSources?: number;
|
|
1674
|
+
/** Vero per i punti d'ingresso del grafo. */
|
|
1675
|
+
isSource: boolean;
|
|
1676
|
+
/** Vero per i sink: producono l'artefatto, non uno schema. */
|
|
1677
|
+
isSink: boolean;
|
|
1678
|
+
/**
|
|
1679
|
+
* Vero dove il backend rifiuta la compilazione pur accettando il modello (**I10**): la UI
|
|
1680
|
+
* deve poter avvisare **prima** che l'utente costruisca la pipeline intorno a un nodo che
|
|
1681
|
+
* non arrivera' all'SQL. Non e' una regola di dominio riprodotta: e' l'informazione che
|
|
1682
|
+
* `docs/domain-model.md` dichiara esplicitamente per queste due categorie, e la
|
|
1683
|
+
* diagnostica autorevole resta `DPE_NODE_NOT_COMPILABLE` del backend.
|
|
1684
|
+
*/
|
|
1685
|
+
isNotCompilableInV1: boolean;
|
|
1686
|
+
}
|
|
1687
|
+
declare const DPE_NODE_CATEGORIES: readonly DpeNodeCategory[];
|
|
1688
|
+
declare function dpeNodeCategory(collection: DpeNodeCollectionName): DpeNodeCategory;
|
|
1689
|
+
/** Nomi dei dialetti per il selettore. La libreria conosce **solo** il nome (ADR 0009). */
|
|
1690
|
+
declare const DPE_DIALECT_LABELS: Readonly<Record<string, string>>;
|
|
1691
|
+
|
|
1692
|
+
/**
|
|
1693
|
+
* I tracciati SVG delle icone di categoria, uno per collezione di nodi.
|
|
1694
|
+
*
|
|
1695
|
+
* **Perche' tracciati e non glifi Unicode** (divergenza motivata dal progetto di riferimento,
|
|
1696
|
+
* `frontend.md` §3-ter): i glifi non hanno metriche ne' linea di base coerenti fra loro e su
|
|
1697
|
+
* alcune piattaforme diventano emoji a colori — cioe' proprio la resa sbagliata quando stanno
|
|
1698
|
+
* in colonna in una palette. Un tracciato disegnato su una griglia 24x24 con `currentColor` si
|
|
1699
|
+
* colora con una sola regola CSS e vale identico in tema chiaro e scuro.
|
|
1700
|
+
*
|
|
1701
|
+
* **Nessun asset e nessuna dipendenza**: sono stringhe, e il componente che le rende le lega con
|
|
1702
|
+
* `[attr.d]` senza mai toccare `innerHTML` — quindi niente `bypassSecurityTrust*`.
|
|
1703
|
+
*
|
|
1704
|
+
* Il disegno e' pensato per la resa a **16px**: pochi tratti, nessun dettaglio sotto i 2 px di
|
|
1705
|
+
* griglia, e sagome che restano distinguibili l'una dall'altra quando sono incolonnate.
|
|
1706
|
+
*/
|
|
1707
|
+
|
|
1708
|
+
/**
|
|
1709
|
+
* La famiglia cromatica di una categoria. **Non e' una tassonomia nuova**: si deriva per intero
|
|
1710
|
+
* da `isSource`/`isSink`/`isNotCompilableInV1` del catalogo, che restano l'unica descrizione dei
|
|
1711
|
+
* tipi di nodo. Serve solo a scegliere un colore.
|
|
1712
|
+
*/
|
|
1713
|
+
type DpeNodeIconFamily = 'source' | 'transform' | 'sink' | 'uncompilable';
|
|
1714
|
+
declare function dpeNodeIconFamily(collection: DpeNodeCollectionName): DpeNodeIconFamily;
|
|
1715
|
+
/** Classe CSS della famiglia: un solo posto la costruisce, cosi' i fogli restano allineati. */
|
|
1716
|
+
declare function dpeNodeIconFamilyClass(collection: DpeNodeCollectionName): string;
|
|
1717
|
+
/**
|
|
1718
|
+
* I tracciati, per collezione. Ogni voce e' l'elenco degli attributi `d` di un `<path>`; il
|
|
1719
|
+
* contorno e' `stroke`, mai `fill`, cosi' l'icona pesa uguale su qualunque sfondo.
|
|
1720
|
+
*/
|
|
1721
|
+
declare const DPE_NODE_ICON_PATHS: Readonly<Record<DpeNodeCollectionName, readonly string[]>>;
|
|
1722
|
+
/**
|
|
1723
|
+
* I tracciati di una collezione. Il ripiego vuoto non e' pigrizia: una collezione aggiunta al
|
|
1724
|
+
* modello e non ancora disegnata deve produrre una pastiglia vuota, non un errore in console
|
|
1725
|
+
* ne' un `undefined` dentro `[attr.d]`.
|
|
1726
|
+
*/
|
|
1727
|
+
declare function dpeNodeIconPaths(collection: DpeNodeCollectionName): readonly string[];
|
|
1728
|
+
|
|
1729
|
+
/**
|
|
1730
|
+
* Creazione di un nodo nuovo: nome candidato e valori iniziali per categoria.
|
|
1731
|
+
*
|
|
1732
|
+
* Non e' validazione e non e' dominio. Serve a una cosa sola: un nodo appena rilasciato sul
|
|
1733
|
+
* canvas deve essere **rappresentabile** e distinguibile, cioe' avere un nome e un'etichetta.
|
|
1734
|
+
* Tutto il resto lo compila l'utente nell'ispettore, e cosa sia obbligatorio lo dice il
|
|
1735
|
+
* backend.
|
|
1736
|
+
*
|
|
1737
|
+
* Il nome candidato e' unico rispetto ai nomi già presenti con confronto **esatto**
|
|
1738
|
+
* (`contracts.md` §2: unicita' verificata `OrdinalIgnoreCase`, risoluzione `Ordinal`). Qui il
|
|
1739
|
+
* confronto e' insensibile al caso di proposito: proporre `Filtro2` accanto a un `filtro2`
|
|
1740
|
+
* esistente creerebbe un `DPE_MODEL_NAME_DUPLICATE` a nome dell'editor, non dell'utente.
|
|
1741
|
+
*/
|
|
1742
|
+
|
|
1743
|
+
/** Il primo nome libero della forma `<radice><n>`. */
|
|
1744
|
+
declare function dpeProposeNodeName(definition: DpeDefinition, collection: DpeNodeCollectionName): string;
|
|
1745
|
+
/**
|
|
1746
|
+
* Il nodo iniziale di una categoria. I campi obbligatori senza un valore sensato restano
|
|
1747
|
+
* **assenti**, non riempiti con un segnaposto: un `tableName` finto passerebbe la forma e
|
|
1748
|
+
* fallirebbe sul provider di metadati con un errore che l'utente non ha causato.
|
|
1749
|
+
*/
|
|
1750
|
+
declare function dpeCreateNode<K extends DpeNodeCollectionName>(definition: DpeDefinition, collection: K): DpeNodeCollectionMap[K];
|
|
1751
|
+
/**
|
|
1752
|
+
* La sequenza dei sink e' univoca fra writeback e gruppi atomici: si propone la prima libera.
|
|
1753
|
+
* L'unicita' la verifica il backend (`DPE_WRITEBACK_SEQUENCE_DUPLICATE`) — questo e' solo un
|
|
1754
|
+
* valore iniziale che non collide, non un controllo.
|
|
1755
|
+
*/
|
|
1756
|
+
declare function dpeProposeWritebackSequence(definition: DpeDefinition): number;
|
|
1757
|
+
/** Etichetta di sintesi mostrata sulla card del nodo, sotto il nome. */
|
|
1758
|
+
declare function dpeNodeSubtitle(collection: DpeNodeCollectionName, node: DpeAnyNode): string | null;
|
|
1759
|
+
|
|
1760
|
+
declare class DpeValidationService {
|
|
1761
|
+
private readonly api;
|
|
1762
|
+
private readonly store;
|
|
1763
|
+
private readonly destroyRef;
|
|
1764
|
+
private readonly _isValidating;
|
|
1765
|
+
private readonly _isCompiling;
|
|
1766
|
+
private readonly _error;
|
|
1767
|
+
/**
|
|
1768
|
+
* Le primitive opzionali si sanno **alla costruzione**, per identita' del metodo
|
|
1769
|
+
* (`dpe-capabilities.ts`, `contracts.md` §7). Prima si partiva da «disponibile» e si scopriva
|
|
1770
|
+
* l'assenza dal primo `MissingService`: il comando sembrava attivo e falliva alla pressione,
|
|
1771
|
+
* che e' peggio di un comando disabilitato che ne dice il motivo.
|
|
1772
|
+
*/
|
|
1773
|
+
private readonly capabilities;
|
|
1774
|
+
private readonly _isPreviewAvailable;
|
|
1775
|
+
private readonly _isSaving;
|
|
1776
|
+
/** Come l'anteprima: un host senza `save` disabilita il comando, non rompe l'editor. */
|
|
1777
|
+
private readonly _isSaveAvailable;
|
|
1778
|
+
/** Esito dell'ultimo salvataggio: transitorio al successo, persistente al fallimento. */
|
|
1779
|
+
private readonly _justSaved;
|
|
1780
|
+
private readonly _saveError;
|
|
1781
|
+
/**
|
|
1782
|
+
* Il dialetto **dichiarato dall'ambiente** (ADR 0017), quando l'host espone `getEnvironment`.
|
|
1783
|
+
* Non e' il dialetto con cui si compila — quello sta nella definizione — ed e' esattamente per
|
|
1784
|
+
* questo che i due si tengono separati: il confronto e' l'unica cosa che l'editor puo' dire.
|
|
1785
|
+
*/
|
|
1786
|
+
private readonly _environmentDialect;
|
|
1787
|
+
readonly isValidating: _angular_core.Signal<boolean>;
|
|
1788
|
+
readonly isCompiling: _angular_core.Signal<boolean>;
|
|
1789
|
+
readonly error: _angular_core.Signal<DpeApiError | undefined>;
|
|
1790
|
+
readonly isPreviewAvailable: _angular_core.Signal<boolean>;
|
|
1791
|
+
readonly isSaving: _angular_core.Signal<boolean>;
|
|
1792
|
+
readonly isSaveAvailable: _angular_core.Signal<boolean>;
|
|
1793
|
+
readonly justSaved: _angular_core.Signal<boolean>;
|
|
1794
|
+
readonly saveError: _angular_core.Signal<DpeApiError | undefined>;
|
|
1795
|
+
readonly environmentDialect: _angular_core.Signal<SqlDialectKind | undefined>;
|
|
1796
|
+
/** Vero finche' non e' arrivata la prima risposta: la UI non deve dire "nessun problema". */
|
|
1797
|
+
readonly hasResult: _angular_core.Signal<boolean>;
|
|
1798
|
+
constructor();
|
|
1799
|
+
/** Anteprima dell'SQL. Opzionale sull'host: assente, il comando resta disabilitato. */
|
|
1800
|
+
requestPreview(parameterValues?: DpeParameterValue[]): void;
|
|
1801
|
+
/**
|
|
1802
|
+
* Salvataggio attraverso `DpeBuilderApi.save` (opzionale, `contracts.md` §7). Al successo
|
|
1803
|
+
* **l'editor dichiara da se'** lo stato salvato: quando l'ospite espone il metodo, e' questo il
|
|
1804
|
+
* punto che sa se e' andato a buon fine.
|
|
1805
|
+
*
|
|
1806
|
+
* Si passa a `markSaved` **il documento inviato**, non quello corrente: se l'utente scrive
|
|
1807
|
+
* mentre il salvataggio e' in volo, quelle modifiche non sono state salvate e l'indicatore deve
|
|
1808
|
+
* continuare a dirlo.
|
|
1809
|
+
*/
|
|
1810
|
+
save(): void;
|
|
1811
|
+
dismissError(): void;
|
|
1812
|
+
dismissSaveError(): void;
|
|
1813
|
+
private saveNoticeTimer;
|
|
1814
|
+
private showSaveNotice;
|
|
1815
|
+
private clearSaveNotice;
|
|
1816
|
+
/**
|
|
1817
|
+
* Un host che non usa `DpeApiError` non deve far esplodere l'editor: cio' che non e'
|
|
1818
|
+
* categorizzato diventa `Transport`, che e' la categoria "riprovabile".
|
|
1819
|
+
*/
|
|
1820
|
+
private toApiError;
|
|
1821
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeValidationService, never>;
|
|
1822
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DpeValidationService>;
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
/**
|
|
1826
|
+
* Geometria della viewport: funzioni pure, nessun DOM.
|
|
1827
|
+
*
|
|
1828
|
+
* Serve a una sola domanda, che si pone quando si naviga da una diagnostica al nodo: **il nodo
|
|
1829
|
+
* e' interamente in vista?** Se lo e', non si sposta niente — una panoramica non richiesta
|
|
1830
|
+
* disorienta quanto la sua assenza. Se non lo e', si centra la **vista**, non il nodo: le
|
|
1831
|
+
* coordinate del documento non si toccano.
|
|
1832
|
+
*
|
|
1833
|
+
* Sta qui e non nel componente perche' e' esattamente il tipo di logica che si sbaglia in
|
|
1834
|
+
* silenzio (un `>` al posto di un `>=`, un margine dimenticato) e che si verifica senza browser.
|
|
1835
|
+
*/
|
|
1836
|
+
/** Rettangolo in coordinate di schermo, la forma che `getBoundingClientRect` restituisce. */
|
|
1837
|
+
interface DpeRect {
|
|
1838
|
+
left: number;
|
|
1839
|
+
top: number;
|
|
1840
|
+
right: number;
|
|
1841
|
+
bottom: number;
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Vero quando `target` sta **interamente** dentro `view`, lasciando `margin` pixel di respiro su
|
|
1845
|
+
* ogni lato. Il margine non e' un vezzo: un nodo tangente al bordo e' tecnicamente visibile e
|
|
1846
|
+
* praticamente illeggibile, e senza respiro il criterio "e' visibile" scatterebbe anche quando
|
|
1847
|
+
* dell'ombra e del connettore di uscita non si vede nulla.
|
|
1848
|
+
*/
|
|
1849
|
+
declare function dpeIsRectFullyVisible(target: DpeRect, view: DpeRect, margin?: number): boolean;
|
|
1850
|
+
|
|
1851
|
+
/** Le tre viste in basso: una alla volta, perche' guardano la stessa cosa da tre angoli. */
|
|
1852
|
+
type DpeBottomTab = 'diagnostics' | 'schema' | 'sql';
|
|
1853
|
+
declare class DpeBuilderComponent {
|
|
1854
|
+
protected readonly store: DpeDocumentStore;
|
|
1855
|
+
protected readonly validation: DpeValidationService;
|
|
1856
|
+
private readonly layout;
|
|
1857
|
+
/** La definizione da editare. Cambiarne l'identita' ricarica il documento. */
|
|
1858
|
+
readonly definition: _angular_core.InputSignal<DpeDefinition>;
|
|
1859
|
+
readonly isEditable: _angular_core.InputSignal<boolean>;
|
|
1860
|
+
/**
|
|
1861
|
+
* Emessa a ogni mutazione. L'ospite **non deve** rimandarla dentro `definition`: sarebbe un
|
|
1862
|
+
* ciclo, e ricaricare azzera la cronologia. Serve per salvare, non per pilotare l'editor.
|
|
1863
|
+
*/
|
|
1864
|
+
readonly definitionChange: _angular_core.OutputEmitterRef<DpeDefinition>;
|
|
1865
|
+
protected readonly dialectLabels: Readonly<Record<string, string>>;
|
|
1866
|
+
protected readonly bottomTab: _angular_core.WritableSignal<DpeBottomTab>;
|
|
1867
|
+
private readonly canvas;
|
|
1868
|
+
/**
|
|
1869
|
+
* Il dialetto **della definizione**: e' quello con cui il backend compilera' (ADR 0009), quindi
|
|
1870
|
+
* e' quello che il badge mostra. In sola lettura: nessun comando dell'interfaccia lo cambia
|
|
1871
|
+
* (ADR 0017), perche' il database di destinazione e' un fatto dell'ambiente e non una
|
|
1872
|
+
* preferenza dell'autore.
|
|
1873
|
+
*/
|
|
1874
|
+
protected readonly dialect: Signal<SqlDialectKind>;
|
|
1875
|
+
/**
|
|
1876
|
+
* Disallineamento fra cio' che l'ambiente dichiara e cio' che la definizione porta. Si
|
|
1877
|
+
* **segnala** e non si corregge: correggere vorrebbe dire migrare le espressioni SQL native
|
|
1878
|
+
* (ADR 0006), che e' dell'host. Assente `getEnvironment`, non c'e' niente da confrontare.
|
|
1879
|
+
*/
|
|
1880
|
+
protected readonly dialectMismatch: Signal<SqlDialectKind | undefined>;
|
|
1881
|
+
protected readonly canSave: Signal<boolean>;
|
|
1882
|
+
protected readonly nodeCount: Signal<number>;
|
|
1883
|
+
constructor();
|
|
1884
|
+
/** Comando «Riordina»: e' un'azione dell'utente, quindi annullabile e "modifica". */
|
|
1885
|
+
protected runAutoLayout(): void;
|
|
1886
|
+
/**
|
|
1887
|
+
* `isInitial` distingue due cose che dagre calcola allo stesso modo e che l'editor deve trattare
|
|
1888
|
+
* in modo opposto: disporre un documento che **non porta** coordinate non e' una modifica
|
|
1889
|
+
* dell'utente; riordinare su richiesta lo e'.
|
|
1890
|
+
*/
|
|
1891
|
+
private runLayout;
|
|
1892
|
+
protected onNodeDropped(event: {
|
|
1893
|
+
collection: DpeNodeCollectionName;
|
|
1894
|
+
x: number;
|
|
1895
|
+
y: number;
|
|
1896
|
+
}): void;
|
|
1897
|
+
/** Clic sulla palette (via tastiera compresa): il nodo nasce in un punto libero e prevedibile. */
|
|
1898
|
+
protected onNodeRequested(collection: DpeNodeCollectionName): void;
|
|
1899
|
+
/**
|
|
1900
|
+
* `Ctrl+S` (e `Cmd+S`): stesse condizioni di abilitazione del bottone. `preventDefault` sempre
|
|
1901
|
+
* che la scorciatoia sia nostra, anche quando il salvataggio non e' possibile: lasciare passare
|
|
1902
|
+
* il «salva pagina» del browser proprio dentro un editor sarebbe la risposta sbagliata a un
|
|
1903
|
+
* gesto giusto.
|
|
1904
|
+
*/
|
|
1905
|
+
protected onKeyDown(event: KeyboardEvent): void;
|
|
1906
|
+
/**
|
|
1907
|
+
* Navigazione da una diagnostica: **selezione e vista**. Il `DiagnosticPath` promette di portare
|
|
1908
|
+
* sul nodo e sul campo; selezionare senza inquadrare mantiene meta' della promessa, e il nodo
|
|
1909
|
+
* resta fuori schermo mentre l'ispettore parla di lui.
|
|
1910
|
+
*/
|
|
1911
|
+
protected onNavigate(event: {
|
|
1912
|
+
nodeName: string;
|
|
1913
|
+
}): void;
|
|
1914
|
+
/**
|
|
1915
|
+
* Stato **sporco** del documento, per l'ospite che deve decidere se lasciar navigare via
|
|
1916
|
+
* (ADR 0019). Delega a `DpeDocumentStore.isDirty`.
|
|
1917
|
+
*
|
|
1918
|
+
* Si legge tramite `viewChild` **quando serve**, non si rispecchia in uno stato dell'ospite: un
|
|
1919
|
+
* mirror di stato sporco che va fuori sincrono e' peggio del problema che risolve. La conferma
|
|
1920
|
+
* prima di abbandonare le modifiche e' dell'ospite, perche' e' l'ospite che naviga — la libreria
|
|
1921
|
+
* non sa se andare via significhi cambiare schermata, scheda o applicazione.
|
|
1922
|
+
*/
|
|
1923
|
+
readonly isDirty: Signal<boolean>;
|
|
1924
|
+
/**
|
|
1925
|
+
* Da chiamare dopo un salvataggio riuscito: da quel momento il documento risulta "senza
|
|
1926
|
+
* modifiche". Lo decide l'ospite, perche' solo lui sa se il salvataggio e' andato a buon fine.
|
|
1927
|
+
*/
|
|
1928
|
+
markSaved(): void;
|
|
1929
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeBuilderComponent, never>;
|
|
1930
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeBuilderComponent, "dpe-builder", never, { "definition": { "alias": "definition"; "required": true; "isSignal": true; }; "isEditable": { "alias": "isEditable"; "required": false; "isSignal": true; }; }, { "definitionChange": "definitionChange"; }, never, never, true, never>;
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/**
|
|
1934
|
+
* View model del canvas.
|
|
1935
|
+
*
|
|
1936
|
+
* Gli **id** non si costruiscono qui: vengono da `core/dpe-graph.ts`, che e' l'unico posto che
|
|
1937
|
+
* li conosce. Qui stanno solo le misure, e stanno qui perche' servono a due consumatori che
|
|
1938
|
+
* devono concordare: il CSS che disegna la card e dagre che calcola il layout. Se divergono,
|
|
1939
|
+
* il layout automatico lascia i nodi sovrapposti.
|
|
1940
|
+
*/
|
|
1941
|
+
|
|
1942
|
+
/** Altezza nominale della card: non cambia con il numero di porte, che stanno in fila sopra. */
|
|
1943
|
+
declare const DPE_NODE_HEIGHT = 104;
|
|
1944
|
+
declare function dpeNodeWidth(portCount: number): number;
|
|
1945
|
+
declare function dpeNodeWidthClass(portCount: number): string;
|
|
1946
|
+
interface DpeCanvasPort {
|
|
1947
|
+
id: string;
|
|
1948
|
+
slot: string;
|
|
1949
|
+
index?: number;
|
|
1950
|
+
/** Etichetta della porta: si mostra solo dove le porte sono piu' di una. */
|
|
1951
|
+
label: string;
|
|
1952
|
+
/** Nome collegato, assente se la porta e' libera. */
|
|
1953
|
+
sourceName?: string;
|
|
1954
|
+
/** Il nome collegato non corrisponde a nessun nodo: si dice sulla porta. */
|
|
1955
|
+
isBroken: boolean;
|
|
1956
|
+
}
|
|
1957
|
+
interface DpeCanvasNode {
|
|
1958
|
+
/** Nome nel documento: l'identita', anche per la selezione. */
|
|
1959
|
+
name: string;
|
|
1960
|
+
/** Id per il canvas, costruito da `dpeNodeId`. */
|
|
1961
|
+
id: string;
|
|
1962
|
+
collection: DpeNodeCollectionName;
|
|
1963
|
+
categoryLabel: string;
|
|
1964
|
+
label: string;
|
|
1965
|
+
subtitle: string | null;
|
|
1966
|
+
position: {
|
|
1967
|
+
x: number;
|
|
1968
|
+
y: number;
|
|
1969
|
+
};
|
|
1970
|
+
ports: DpeCanvasPort[];
|
|
1971
|
+
showsPortLabels: boolean;
|
|
1972
|
+
widthClass: string;
|
|
1973
|
+
/**
|
|
1974
|
+
* Classe della famiglia cromatica (`dpe-cat--*`): la calcola `core/dpe-node-icons.ts` dai
|
|
1975
|
+
* flag del catalogo. Sta nel view model e non nel template perche' e' la stessa che usa la
|
|
1976
|
+
* palette, e due modi di derivarla sarebbero due colori diversi per lo stesso tipo di nodo.
|
|
1977
|
+
*/
|
|
1978
|
+
familyClass: string;
|
|
1979
|
+
outputPortId: string;
|
|
1980
|
+
/** I sink non producono uno schema: la porta di uscita non si disegna... */
|
|
1981
|
+
hasOutput: boolean;
|
|
1982
|
+
/** Gravita' peggiore fra le diagnostiche del nodo. */
|
|
1983
|
+
severity: DiagnosticSeverity | null;
|
|
1984
|
+
diagnosticCount: number;
|
|
1985
|
+
/**
|
|
1986
|
+
* Nodo **valido ma non compilabile** (**I10**): stato distinto da "non valido", con un
|
|
1987
|
+
* colore proprio. Sono due situazioni diverse e l'utente deve capire subito quale guarda.
|
|
1988
|
+
*/
|
|
1989
|
+
isNotCompilable: boolean;
|
|
1990
|
+
/** Numero di colonne dello schema di uscita, quando il backend lo ha detto. */
|
|
1991
|
+
columnCount: number | null;
|
|
1992
|
+
}
|
|
1993
|
+
interface DpeCanvasEdge {
|
|
1994
|
+
id: string;
|
|
1995
|
+
sourceId: string;
|
|
1996
|
+
targetId: string;
|
|
1997
|
+
slot: string;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
declare class DpeCanvasComponent {
|
|
2001
|
+
private readonly store;
|
|
2002
|
+
/** Serve per misurare l'area disponibile prima di decidere la scala d'apertura. */
|
|
2003
|
+
private readonly host;
|
|
2004
|
+
/** Marker "all states": senza, l'arco selezionato perde la punta. */
|
|
2005
|
+
readonly markerEnd = EFMarkerType.END_ALL_STATES;
|
|
2006
|
+
/**
|
|
2007
|
+
* Ingressi in alto, uscita in basso, **dichiarati**. Lasciando calcolare il lato, un arco
|
|
2008
|
+
* che risale (un nodo posizionato sopra la sua sorgente) esce di fianco e il grafo diventa
|
|
2009
|
+
* illeggibile.
|
|
2010
|
+
*/
|
|
2011
|
+
readonly sides: typeof EFConnectableSide;
|
|
2012
|
+
readonly isEditable: _angular_core.InputSignal<boolean>;
|
|
2013
|
+
readonly nodeOpened: _angular_core.OutputEmitterRef<string>;
|
|
2014
|
+
readonly nodeDropped: _angular_core.OutputEmitterRef<{
|
|
2015
|
+
collection: DpeNodeCollectionName;
|
|
2016
|
+
x: number;
|
|
2017
|
+
y: number;
|
|
2018
|
+
}>;
|
|
2019
|
+
private readonly canvas;
|
|
2020
|
+
/**
|
|
2021
|
+
* Serve solo a **riallineare** la selezione della libreria a quella dello store: e' l'unico
|
|
2022
|
+
* punto che scrive nello stato di selezione di @foblex/flow.
|
|
2023
|
+
*/
|
|
2024
|
+
private readonly flow;
|
|
2025
|
+
private hasFramedOnce;
|
|
2026
|
+
/**
|
|
2027
|
+
* Visibilita' del comando «Inquadra». Non e' piu' «l'utente ha spostato la vista»: lo diventa
|
|
2028
|
+
* anche all'apertura quando l'editor rinuncia a inquadrare per non scendere sotto
|
|
2029
|
+
* `MIN_INITIAL_SCALE`. In quel caso la vista d'insieme non e' stata data, quindi il comando che
|
|
2030
|
+
* la offre deve essere raggiungibile — nasconderlo significherebbe toglierla e basta.
|
|
2031
|
+
*/
|
|
2032
|
+
private readonly _isFitCommandVisible;
|
|
2033
|
+
readonly isFitCommandVisible: _angular_core.Signal<boolean>;
|
|
2034
|
+
readonly nodes: _angular_core.Signal<DpeCanvasNode[]>;
|
|
2035
|
+
/**
|
|
2036
|
+
* Solo gli archi con **entrambi** i capi risolti diventano `<f-connection>`: un capo che non
|
|
2037
|
+
* esiste non ha un connettore, e una connessione verso un id inesistente si attacca a un
|
|
2038
|
+
* punto arbitrario del canvas. Il riferimento rotto si vede sulla porta del nodo.
|
|
2039
|
+
*/
|
|
2040
|
+
readonly edges: _angular_core.Signal<DpeCanvasEdge[]>;
|
|
2041
|
+
constructor();
|
|
2042
|
+
/**
|
|
2043
|
+
* Porta il nodo in vista **muovendo la vista**, non il nodo: le coordinate del documento non si
|
|
2044
|
+
* toccano (una navigazione non e' una modifica). Se il nodo e' gia' interamente visibile non fa
|
|
2045
|
+
* nulla, perche' una panoramica non richiesta disorienta quanto la sua assenza.
|
|
2046
|
+
*/
|
|
2047
|
+
revealNode(name: string): void;
|
|
2048
|
+
/**
|
|
2049
|
+
* Il nodo nel DOM. Si scorre l'elenco invece di comporre un selettore con il valore
|
|
2050
|
+
* dell'attributo: il nome del nodo arriva dal documento e puo' contenere qualunque carattere,
|
|
2051
|
+
* e un selettore costruito per concatenazione su un dato del documento e' un errore in attesa.
|
|
2052
|
+
*/
|
|
2053
|
+
private findNodeElement;
|
|
2054
|
+
/** Misure per il layout automatico: le stesse che il CSS applica con le classi. */
|
|
2055
|
+
layoutInput(): {
|
|
2056
|
+
name: string;
|
|
2057
|
+
width: number;
|
|
2058
|
+
height: number;
|
|
2059
|
+
}[];
|
|
2060
|
+
/**
|
|
2061
|
+
* `fitToScreen` va chiamato **dopo** il render dei nodi: prima, la libreria non conosce
|
|
2062
|
+
* ancora le loro dimensioni e inquadra la vista sbagliata. Solo la prima volta: rifarlo
|
|
2063
|
+
* combatterebbe con l'utente che ha spostato la vista.
|
|
2064
|
+
*/
|
|
2065
|
+
onNodesRendered(): void;
|
|
2066
|
+
/** Vero quando inquadrare tutto il grafo richiederebbe una scala sotto la soglia leggibile. */
|
|
2067
|
+
private wouldFitBelowMinimumScale;
|
|
2068
|
+
onCanvasChange(): void;
|
|
2069
|
+
resetViewport(): void;
|
|
2070
|
+
/**
|
|
2071
|
+
* Creazione di un arco: si scrive il **riferimento** sulla porta di destinazione. La
|
|
2072
|
+
* direzione del gesto e' irrilevante — cio' che conta e' quale slot riceve il nome, ed e'
|
|
2073
|
+
* per questo che le porte di ingresso sono una per slot.
|
|
2074
|
+
*/
|
|
2075
|
+
onCreateConnection(event: {
|
|
2076
|
+
sourceId: string;
|
|
2077
|
+
targetId?: string;
|
|
2078
|
+
}): void;
|
|
2079
|
+
/** Riassegnazione di un arco già disegnato, da un capo o dall'altro. */
|
|
2080
|
+
onReassignConnection(event: {
|
|
2081
|
+
endpoint: string;
|
|
2082
|
+
previousSourceId: string;
|
|
2083
|
+
nextSourceId?: string;
|
|
2084
|
+
previousTargetId: string;
|
|
2085
|
+
nextTargetId?: string;
|
|
2086
|
+
}): void;
|
|
2087
|
+
/**
|
|
2088
|
+
* Spostamento: un solo passo di cronologia per l'intero gesto. Le posizioni intermedie non
|
|
2089
|
+
* sono modifiche che l'utente vuole annullare una per una.
|
|
2090
|
+
*/
|
|
2091
|
+
onMoveNodes(event: {
|
|
2092
|
+
nodes: Array<{
|
|
2093
|
+
id: string;
|
|
2094
|
+
position: {
|
|
2095
|
+
x: number;
|
|
2096
|
+
y: number;
|
|
2097
|
+
};
|
|
2098
|
+
}>;
|
|
2099
|
+
}): void;
|
|
2100
|
+
/**
|
|
2101
|
+
* Il gesto di selezione della libreria entra **nello store** e non altrove: e' l'unico verso in
|
|
2102
|
+
* cui la selezione di @foblex/flow conta, come rilevazione del gesto. Cio' che si vede lo decide
|
|
2103
|
+
* lo store, attraverso l'effect del costruttore.
|
|
2104
|
+
*/
|
|
2105
|
+
onSelectionChange(event: {
|
|
2106
|
+
nodeIds: string[];
|
|
2107
|
+
}): void;
|
|
2108
|
+
onDeleteSelected(event: {
|
|
2109
|
+
nodeIds: string[];
|
|
2110
|
+
}): void;
|
|
2111
|
+
/**
|
|
2112
|
+
* Rilascio di una voce trascinata dalla palette. `externalItemRect` e' già nel sistema di
|
|
2113
|
+
* coordinate del canvas: convertirlo a mano dal viewport sarebbe rifare la trasformazione
|
|
2114
|
+
* di zoom e panoramica della libreria.
|
|
2115
|
+
*/
|
|
2116
|
+
onCreateNode(event: {
|
|
2117
|
+
data: unknown;
|
|
2118
|
+
externalItemRect: {
|
|
2119
|
+
x: number;
|
|
2120
|
+
y: number;
|
|
2121
|
+
};
|
|
2122
|
+
}): void;
|
|
2123
|
+
onNodeDoubleClick(name: string): void;
|
|
2124
|
+
onEditClick(event: Event, name: string): void;
|
|
2125
|
+
onRemoveClick(event: Event, name: string): void;
|
|
2126
|
+
/** La classe nel DOM **deriva** dallo store: non e' una seconda registrazione della selezione. */
|
|
2127
|
+
isSelected(node: DpeCanvasNode): boolean;
|
|
2128
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeCanvasComponent, never>;
|
|
2129
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeCanvasComponent, "dpe-canvas", never, { "isEditable": { "alias": "isEditable"; "required": false; "isSignal": true; }; }, { "nodeOpened": "nodeOpened"; "nodeDropped": "nodeDropped"; }, never, never, true, never>;
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
declare class DpeCatalogComponent {
|
|
2133
|
+
protected readonly store: DpeCatalogStore;
|
|
2134
|
+
private readonly injector;
|
|
2135
|
+
/**
|
|
2136
|
+
* Il **nome** della definizione da aprire. Non la definizione: caricarla e' dell'ospite, che
|
|
2137
|
+
* potrebbe volerlo fare per vie proprie.
|
|
2138
|
+
*/
|
|
2139
|
+
readonly open: _angular_core.OutputEmitterRef<string>;
|
|
2140
|
+
protected readonly dialectLabels: Readonly<Record<string, string>>;
|
|
2141
|
+
/** Filtro **locale** sui sommari gia' ricevuti: non e' una query al backend (ADR 0019). */
|
|
2142
|
+
protected readonly filter: _angular_core.WritableSignal<string>;
|
|
2143
|
+
protected readonly newName: _angular_core.WritableSignal<string>;
|
|
2144
|
+
protected readonly newLabel: _angular_core.WritableSignal<string>;
|
|
2145
|
+
/**
|
|
2146
|
+
* Conferma in **due passi**: un elenco in cui un clic distratto cancella non e' un elenco.
|
|
2147
|
+
* Tiene il nome invece di un booleano perche' la conferma appartiene a **quella** riga.
|
|
2148
|
+
*/
|
|
2149
|
+
protected readonly pendingDelete: _angular_core.WritableSignal<string | null>;
|
|
2150
|
+
/** Riga in duplicazione, con i due campi del nome e dell'etichetta nuovi. */
|
|
2151
|
+
protected readonly duplicateSource: _angular_core.WritableSignal<string | null>;
|
|
2152
|
+
protected readonly duplicateName: _angular_core.WritableSignal<string>;
|
|
2153
|
+
protected readonly duplicateLabel: _angular_core.WritableSignal<string>;
|
|
2154
|
+
private readonly duplicateNameField;
|
|
2155
|
+
/**
|
|
2156
|
+
* Il filtro non tocca l'ordine: si tolgono righe, non si riordinano. `toLocaleLowerCase` e non
|
|
2157
|
+
* `toLowerCase` perche' un elenco di definizioni italiane si filtra anche per lettere accentate.
|
|
2158
|
+
*/
|
|
2159
|
+
protected readonly visible: _angular_core.Signal<readonly DpeDefinitionSummary[]>;
|
|
2160
|
+
/** Vero quando il filtro ha nascosto tutto: e' un messaggio diverso da «nessuna definizione». */
|
|
2161
|
+
protected readonly isFilteredEmpty: _angular_core.Signal<boolean>;
|
|
2162
|
+
/**
|
|
2163
|
+
* Duplicare richiede **due** primitive, `load` e `createDefinition`: non esiste una primitiva
|
|
2164
|
+
* di duplicazione, il comando si compone da queste.
|
|
2165
|
+
*/
|
|
2166
|
+
protected readonly canDuplicate: _angular_core.Signal<boolean>;
|
|
2167
|
+
protected readonly duplicateReason: _angular_core.Signal<"Duplica: carica questa definizione e la ricrea con un nome nuovo" | "Duplicazione non disponibile: questo ambiente non implementa load e createDefinition.">;
|
|
2168
|
+
/** Validazione **di forma**, l'unica ammessa nel frontend: due campi non vuoti. */
|
|
2169
|
+
protected readonly canSubmitNew: _angular_core.Signal<boolean>;
|
|
2170
|
+
protected readonly canSubmitDuplicate: _angular_core.Signal<boolean>;
|
|
2171
|
+
protected onOpen(name: string): void;
|
|
2172
|
+
protected refresh(): void;
|
|
2173
|
+
/**
|
|
2174
|
+
* Crea e **apre il nome tornato dall'ospite**, non quello digitato: l'ospite puo' averlo
|
|
2175
|
+
* normalizzato, e aprire quello digitato aprirebbe una definizione che non esiste.
|
|
2176
|
+
*/
|
|
2177
|
+
protected createNew(): void;
|
|
2178
|
+
protected startDuplicate(summary: DpeDefinitionSummary): void;
|
|
2179
|
+
protected cancelDuplicate(): void;
|
|
2180
|
+
protected confirmDuplicate(): void;
|
|
2181
|
+
protected askDelete(name: string): void;
|
|
2182
|
+
protected cancelDelete(): void;
|
|
2183
|
+
protected confirmDelete(name: string): void;
|
|
2184
|
+
/** Solo la data, senza ora: un elenco non e' un registro di audit. */
|
|
2185
|
+
protected formatDate(value: string): string;
|
|
2186
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeCatalogComponent, never>;
|
|
2187
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeCatalogComponent, "dpe-catalog", never, {}, { "open": "open"; }, never, never, true, never>;
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
/** Un gruppo dell'elenco: intestazione e voci. Presentazione, non semantica. */
|
|
2191
|
+
interface DpeNodePaletteGroup {
|
|
2192
|
+
key: 'sources' | 'transforms' | 'sinks';
|
|
2193
|
+
label: string;
|
|
2194
|
+
categories: readonly DpeNodeCategory[];
|
|
2195
|
+
}
|
|
2196
|
+
declare class DpeNodePaletteComponent {
|
|
2197
|
+
/** Clic sulla voce: il nodo si crea al centro dell'area, non dove stava il puntatore. */
|
|
2198
|
+
readonly nodeRequested: _angular_core.OutputEmitterRef<keyof _esfaenza_dpe_builder.DpeNodeCollectionMap>;
|
|
2199
|
+
protected readonly filter: _angular_core.WritableSignal<string>;
|
|
2200
|
+
readonly visible: _angular_core.Signal<readonly DpeNodeCategory[]>;
|
|
2201
|
+
/**
|
|
2202
|
+
* Tre gruppi, nell'ordine in cui si costruisce una pipeline: da dove entrano i dati, cosa ci
|
|
2203
|
+
* si fa, dove finiscono. I gruppi vuoti non compaiono, altrimenti una ricerca lascerebbe sullo
|
|
2204
|
+
* schermo intestazioni senza voci.
|
|
2205
|
+
*/
|
|
2206
|
+
readonly groups: _angular_core.Signal<readonly DpeNodePaletteGroup[]>;
|
|
2207
|
+
protected familyClass(category: DpeNodeCategory): string;
|
|
2208
|
+
/** Il testo che la descrizione non mostra piu' nel corpo della voce. */
|
|
2209
|
+
protected titleOf(category: DpeNodeCategory): string;
|
|
2210
|
+
protected text(event: Event): string;
|
|
2211
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeNodePaletteComponent, never>;
|
|
2212
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeNodePaletteComponent, "dpe-node-palette", never, {}, { "nodeRequested": "nodeRequested"; }, never, never, true, never>;
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
declare class DpeNodeInspectorComponent {
|
|
2216
|
+
private readonly store;
|
|
2217
|
+
/**
|
|
2218
|
+
* Il riordino richiede le misure delle card, che le conosce il canvas: l'ispettore **chiede**,
|
|
2219
|
+
* non calcola. Componente stupido, orchestrazione fuori.
|
|
2220
|
+
*/
|
|
2221
|
+
readonly layoutRequested: _angular_core.OutputEmitterRef<void>;
|
|
2222
|
+
readonly selectedNames: _angular_core.Signal<readonly string[]>;
|
|
2223
|
+
readonly located: _angular_core.Signal<_esfaenza_dpe_builder.DpeLocatedNode<keyof _esfaenza_dpe_builder.DpeNodeCollectionMap> | undefined>;
|
|
2224
|
+
readonly nameDraft: _angular_core.WritableSignal<string>;
|
|
2225
|
+
readonly categoryLabel: _angular_core.Signal<string>;
|
|
2226
|
+
/** La classe di famiglia dell'icona: la stessa funzione che usano palette e canvas. */
|
|
2227
|
+
readonly familyClass: _angular_core.Signal<string>;
|
|
2228
|
+
readonly columns: _angular_core.Signal<_esfaenza_dpe_builder.DpeColumnInfo[]>;
|
|
2229
|
+
readonly diagnostics: _angular_core.Signal<_esfaenza_dpe_builder.Diagnostic[]>;
|
|
2230
|
+
readonly referenceCount: _angular_core.Signal<number>;
|
|
2231
|
+
readonly canRename: _angular_core.Signal<boolean>;
|
|
2232
|
+
constructor();
|
|
2233
|
+
/**
|
|
2234
|
+
* Elimina i nodi selezionati. Si itera su una **copia** dei nomi: `removeNode` pota la selezione
|
|
2235
|
+
* a ogni giro, e scorrere il signal mentre lo si svuota salterebbe la meta' dei nodi.
|
|
2236
|
+
*/
|
|
2237
|
+
protected removeSelected(): void;
|
|
2238
|
+
protected rename(currentName: string): void;
|
|
2239
|
+
protected setCommon(field: 'label' | 'description', value: string): void;
|
|
2240
|
+
protected valueOf(event: Event): string;
|
|
2241
|
+
protected asDataSource(node: unknown): DataSourceNode;
|
|
2242
|
+
protected asFilter(node: unknown): FilterNode;
|
|
2243
|
+
protected asJoin(node: unknown): JoinNode;
|
|
2244
|
+
protected asAggregate(node: unknown): AggregateNode;
|
|
2245
|
+
protected asTransform(node: unknown): TransformNode;
|
|
2246
|
+
protected asAppend(node: unknown): AppendNode;
|
|
2247
|
+
protected asHierarchy(node: unknown): HierarchyPathNode;
|
|
2248
|
+
protected asForecast(node: unknown): ForecastNode;
|
|
2249
|
+
protected asCustom(node: unknown): CustomNode;
|
|
2250
|
+
protected asWriteback(node: unknown): WritebackNode;
|
|
2251
|
+
protected asAtomic(node: unknown): AtomicWritebackNode;
|
|
2252
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeNodeInspectorComponent, never>;
|
|
2253
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeNodeInspectorComponent, "dpe-node-inspector", never, {}, { "layoutRequested": "layoutRequested"; }, never, never, true, never>;
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
declare abstract class DpeNodeInspectorBase<TNode extends DpeAnyNode = DpeAnyNode> {
|
|
2257
|
+
protected readonly store: DpeDocumentStore;
|
|
2258
|
+
readonly nodeName: _angular_core.InputSignal<string>;
|
|
2259
|
+
readonly node: _angular_core.InputSignal<TNode>;
|
|
2260
|
+
/** La collezione di appartenenza: la sa l'ispettore, serve per scrivere nello store. */
|
|
2261
|
+
abstract readonly collection: DpeNodeCollectionName;
|
|
2262
|
+
/** Le diagnostiche ancorate a questo nodo, come le ha date il backend (**I6**). */
|
|
2263
|
+
readonly diagnostics: _angular_core.Signal<readonly Diagnostic[]>;
|
|
2264
|
+
/**
|
|
2265
|
+
* Il nodo e' valido ma non compilabile (**I10**): l'ispettore lo dice in testa, perche' e'
|
|
2266
|
+
* l'informazione che spiega perche' non compare nessun SQL — e non c'e' niente da correggere.
|
|
2267
|
+
*/
|
|
2268
|
+
readonly isNotCompilable: _angular_core.Signal<boolean>;
|
|
2269
|
+
/** Colonne prodotte dal nodo, secondo il backend. Mai calcolate qui (**I4**). */
|
|
2270
|
+
readonly outputColumns: _angular_core.Signal<readonly DpeColumnInfo[]>;
|
|
2271
|
+
/**
|
|
2272
|
+
* Colonne disponibili **in ingresso**: l'unione degli schemi dei nodi a monte, nell'ordine.
|
|
2273
|
+
* Arrivano dal backend; se la validazione non e' ancora tornata l'elenco e' vuoto e i campi
|
|
2274
|
+
* si digitano a mano — che e' meglio di un elenco indovinato in locale.
|
|
2275
|
+
*/
|
|
2276
|
+
readonly inputColumns: _angular_core.Signal<readonly DpeColumnInfo[]>;
|
|
2277
|
+
/** I parametri dichiarati sulla radice: servono a filtri e mapping dei writeback. */
|
|
2278
|
+
readonly parameters: _angular_core.Signal<_esfaenza_dpe_builder.DpeParameter[]>;
|
|
2279
|
+
/** Le diagnostiche su un campo preciso, per mostrarle **accanto** al controllo. */
|
|
2280
|
+
issuesOn(field: string): Diagnostic[];
|
|
2281
|
+
hasIssueOn(field: string): boolean;
|
|
2282
|
+
/** Applica una modifica al nodo. */
|
|
2283
|
+
protected patch(patch: Partial<TNode>): void;
|
|
2284
|
+
/**
|
|
2285
|
+
* Campo semplice: valore vuoto → chiave **rimossa**, non stringa vuota. Il backend
|
|
2286
|
+
* distingue assente da vuoto (`DPE_MODEL_REQUIRED_MISSING` contro un valore non valido), e
|
|
2287
|
+
* su Oracle la stringa vuota **e'** `NULL`: scriverla al posto di un'assenza cambia la
|
|
2288
|
+
* semantica invece di ripulire il campo.
|
|
2289
|
+
*/
|
|
2290
|
+
protected setField(field: keyof TNode & string, value: unknown): void;
|
|
2291
|
+
/** Numero da un campo di testo: vuoto o non numerico → assente, non `0`. */
|
|
2292
|
+
protected toNumber(value: string): number | undefined;
|
|
2293
|
+
/** Lettura tipizzata di un valore da un evento di input, senza `any` nei template. */
|
|
2294
|
+
protected valueOf(event: Event): string;
|
|
2295
|
+
protected checkedOf(event: Event): boolean;
|
|
2296
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeNodeInspectorBase<any>, never>;
|
|
2297
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<DpeNodeInspectorBase<any>, never, never, { "nodeName": { "alias": "nodeName"; "required": true; "isSignal": true; }; "node": { "alias": "node"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
interface DpeDiagnosticRow {
|
|
2301
|
+
diagnostic: Diagnostic;
|
|
2302
|
+
location: string;
|
|
2303
|
+
/** Nodo a cui navigare, se il percorso permette di ricavarlo. */
|
|
2304
|
+
nodeName?: string;
|
|
2305
|
+
field?: string;
|
|
2306
|
+
isNotCompilable: boolean;
|
|
2307
|
+
isDialect: boolean;
|
|
2308
|
+
}
|
|
2309
|
+
declare class DpeDiagnosticsPanelComponent {
|
|
2310
|
+
private readonly store;
|
|
2311
|
+
/** Emesso quando la riga porta a un nodo: chi ascolta apre l'ispettore e inquadra il nodo. */
|
|
2312
|
+
readonly navigate: _angular_core.OutputEmitterRef<{
|
|
2313
|
+
nodeName: string;
|
|
2314
|
+
field?: string;
|
|
2315
|
+
}>;
|
|
2316
|
+
readonly hasResult: _angular_core.Signal<boolean>;
|
|
2317
|
+
readonly dialectLabel: _angular_core.Signal<string>;
|
|
2318
|
+
readonly rows: _angular_core.Signal<DpeDiagnosticRow[]>;
|
|
2319
|
+
readonly counts: _angular_core.Signal<{
|
|
2320
|
+
errors: number;
|
|
2321
|
+
warnings: number;
|
|
2322
|
+
infos: number;
|
|
2323
|
+
notCompilable: number;
|
|
2324
|
+
}>;
|
|
2325
|
+
/**
|
|
2326
|
+
* Emette **soltanto** l'intenzione: chi la riceve seleziona e inquadra. Selezionare anche da qui
|
|
2327
|
+
* significherebbe due scritture della selezione per un solo clic — la strada per due nodi
|
|
2328
|
+
* selezionati insieme — e un pannello che pilota il canvas invece di chiederglielo.
|
|
2329
|
+
*/
|
|
2330
|
+
protected navigateTo(row: DpeDiagnosticRow): void;
|
|
2331
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeDiagnosticsPanelComponent, never>;
|
|
2332
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeDiagnosticsPanelComponent, "dpe-diagnostics-panel", never, {}, { "navigate": "navigate"; }, never, never, true, never>;
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
interface DpeSchemaRow {
|
|
2336
|
+
nodeName: string;
|
|
2337
|
+
categoryLabel: string;
|
|
2338
|
+
isSelected: boolean;
|
|
2339
|
+
isCompilable: boolean;
|
|
2340
|
+
hasSchema: boolean;
|
|
2341
|
+
inputColumns: readonly DpeColumnInfo[];
|
|
2342
|
+
outputColumns: readonly DpeColumnInfo[];
|
|
2343
|
+
/** Colonne in uscita che non esistono in ingresso: alias nuovi o colonne prodotte dal nodo. */
|
|
2344
|
+
introduced: ReadonlySet<string>;
|
|
2345
|
+
/** Colonne in ingresso che non arrivano in uscita: eliminate o rinominate. */
|
|
2346
|
+
dropped: readonly string[];
|
|
2347
|
+
}
|
|
2348
|
+
declare class DpeSchemaPanelComponent {
|
|
2349
|
+
private readonly store;
|
|
2350
|
+
readonly hasResult: _angular_core.Signal<boolean>;
|
|
2351
|
+
readonly rows: _angular_core.Signal<DpeSchemaRow[]>;
|
|
2352
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeSchemaPanelComponent, never>;
|
|
2353
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeSchemaPanelComponent, "dpe-schema-panel", never, {}, {}, never, never, true, never>;
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
interface DpeSqlSection {
|
|
2357
|
+
title: string;
|
|
2358
|
+
hint: string;
|
|
2359
|
+
writebacks: readonly DpeCompiledWriteback[];
|
|
2360
|
+
}
|
|
2361
|
+
declare class DpeSqlPreviewComponent {
|
|
2362
|
+
private readonly store;
|
|
2363
|
+
protected readonly validation: DpeValidationService;
|
|
2364
|
+
readonly result: _angular_core.Signal<_esfaenza_dpe_builder.DpeCompileResult | undefined>;
|
|
2365
|
+
readonly sections: _angular_core.Signal<DpeSqlSection[]>;
|
|
2366
|
+
readonly isEmpty: _angular_core.Signal<boolean>;
|
|
2367
|
+
/** Il valore di un parametro e' opaco: si mostra, non si converte. */
|
|
2368
|
+
protected display(value: unknown): string;
|
|
2369
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeSqlPreviewComponent, never>;
|
|
2370
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeSqlPreviewComponent, "dpe-sql-preview", never, {}, {}, never, never, true, never>;
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
declare class DpeExpressionEditorComponent {
|
|
2374
|
+
readonly label: _angular_core.InputSignal<string>;
|
|
2375
|
+
readonly value: _angular_core.InputSignal<string | undefined>;
|
|
2376
|
+
readonly placeholder: _angular_core.InputSignal<string>;
|
|
2377
|
+
readonly dialect: _angular_core.InputSignal<SqlDialectKind>;
|
|
2378
|
+
/**
|
|
2379
|
+
* I nomi delle colonne a monte, **come suggerimento** e non come elenco chiuso: sono cio'
|
|
2380
|
+
* che il backend ha propagato, ma dentro l'espressione si puo' scrivere qualunque SQL.
|
|
2381
|
+
*/
|
|
2382
|
+
readonly columns: _angular_core.InputSignal<readonly string[]>;
|
|
2383
|
+
readonly controlId: _angular_core.InputSignal<string>;
|
|
2384
|
+
readonly valueChange: _angular_core.OutputEmitterRef<string>;
|
|
2385
|
+
readonly dialectLabel: _angular_core.Signal<string>;
|
|
2386
|
+
/** Elenco troncato: dieci nomi sono un aiuto, cinquanta sono un muro di testo. */
|
|
2387
|
+
readonly columnHint: _angular_core.Signal<string>;
|
|
2388
|
+
protected text(event: Event): string;
|
|
2389
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeExpressionEditorComponent, never>;
|
|
2390
|
+
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>;
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
declare class DpeColumnTypeEditorComponent {
|
|
2394
|
+
readonly value: _angular_core.InputSignal<ColumnType | undefined>;
|
|
2395
|
+
readonly controlId: _angular_core.InputSignal<string>;
|
|
2396
|
+
readonly valueChange: _angular_core.OutputEmitterRef<ColumnType>;
|
|
2397
|
+
protected readonly types: readonly LogicalType[];
|
|
2398
|
+
readonly kind: _angular_core.Signal<LogicalType>;
|
|
2399
|
+
readonly allowedValues: _angular_core.Signal<string>;
|
|
2400
|
+
protected onKind(kind: string): void;
|
|
2401
|
+
protected onNumber(field: 'length' | 'precision' | 'scale', raw: string): void;
|
|
2402
|
+
protected onAllowedValues(raw: string): void;
|
|
2403
|
+
protected text(event: Event): string;
|
|
2404
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeColumnTypeEditorComponent, never>;
|
|
2405
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeColumnTypeEditorComponent, "dpe-column-type-editor", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
declare class DpeSelectValueDirective implements AfterViewChecked {
|
|
2409
|
+
private readonly element;
|
|
2410
|
+
readonly dpeValue: _angular_core.InputSignal<string | number | null | undefined>;
|
|
2411
|
+
ngAfterViewChecked(): void;
|
|
2412
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeSelectValueDirective, never>;
|
|
2413
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<DpeSelectValueDirective, "select[dpeValue]", never, { "dpeValue": { "alias": "dpeValue"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
declare class DpeNodeIconComponent {
|
|
2417
|
+
readonly collection: _angular_core.InputSignal<keyof _esfaenza_dpe_builder.DpeNodeCollectionMap>;
|
|
2418
|
+
protected readonly paths: _angular_core.Signal<readonly string[]>;
|
|
2419
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DpeNodeIconComponent, never>;
|
|
2420
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DpeNodeIconComponent, "dpe-node-icon", never, { "collection": { "alias": "collection"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
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, 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 };
|
|
2424
|
+
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 };
|