@esfaenza/dpe-builder 20.3.14 → 20.3.15

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.
@@ -1146,10 +1146,24 @@ function dpeIsNodeCollectionName(value) {
1146
1146
  * `node`; l'indice del primo segmento risolto nella collezione corrispondente della
1147
1147
  * definizione — che e' il caso della deserializzazione, dove i nomi non sono ancora noti.
1148
1148
  * Senza la terza, un `filters[0].sourceName` resterebbe una riga non cliccabile.
1149
+ *
1150
+ * La prima e la terza strada valgono solo se la radice del percorso e' una collezione di nodi
1151
+ * (`contracts.md` §1, normativo; questione aperta 39).
1149
1152
  */
1150
1153
  function dpeDiagnosticNodeName(diagnostic, definition) {
1151
1154
  const first = diagnostic.path?.segments?.[0];
1152
- if (first?.name) {
1155
+ /*
1156
+ * Il backend emette primi segmenti con un nome che non sono nodi: `parameters/<nome>` dalla
1157
+ * validazione, `restrictions/<writeback>` e `artifactPlan/<writeback>` dalle utility. Senza il
1158
+ * controllo il nome del parametro tornava come nodo — riga cliccabile verso un nodo che non
1159
+ * esiste, e diagnostica sparita da quelle della definizione. `artifactPlan` portava al
1160
+ * writeback solo per coincidenza di nome, contro l'intento dell'emettitore: smette apposta.
1161
+ * Il confronto e' esatto con i nomi del modello, senza varianti, perche' il contratto impone
1162
+ * alle collezioni di nodi la sola grafia del modello in ogni forma del percorso: se un livello
1163
+ * ne scrivesse un'altra, la navigazione di quel tipo di nodo si spegnerebbe in silenzio, e il
1164
+ * rimedio e' nel backend, non in un elenco di grafie qui.
1165
+ */
1166
+ if (first?.name && dpeIsNodeCollectionName(first.collection)) {
1153
1167
  return first.name;
1154
1168
  }
1155
1169
  const fromArguments = diagnostic.arguments?.['node'];
@@ -1248,19 +1262,69 @@ function dpeGroupDiagnosticsByNode(diagnostics, definition) {
1248
1262
  function dpeDefinitionLevelDiagnostics(diagnostics, definition) {
1249
1263
  return diagnostics.filter((diagnostic) => dpeDiagnosticNodeName(diagnostic, definition) === undefined);
1250
1264
  }
1265
+ /**
1266
+ * Le parole con cui si legge il primo segmento quando la sua radice non e' una collezione di nodi.
1267
+ * Le tre radici sono quelle che `contracts.md` §1 dichiara non-nodo; per `restrictions` e
1268
+ * `artifactPlan` il nome e' **del writeback**, non della cosa, e la preposizione lo dice — per
1269
+ * questo la preposizione sta solo davanti al nome, e non davanti all'indice.
1270
+ *
1271
+ * E' un elenco scritto qui, ma non e' l'opzione C della questione 39 rientrata dalla finestra:
1272
+ * governa solo il testo, non la navigazione, e una radice che non vi compare non sparisce — si
1273
+ * legge grezza, come i segmenti successivi. Il difetto che l'elenco puo' avere e' una parola
1274
+ * italiana mancante, non un elemento nascosto o un nodo inventato.
1275
+ *
1276
+ * `Map` e non oggetto letterale: la chiave arriva dal backend, e su un oggetto una radice che si
1277
+ * chiamasse `constructor` o `toString` troverebbe una funzione del prototipo.
1278
+ */
1279
+ const NON_NODE_ROOT_WORDS = new Map([
1280
+ ['parameters', { noun: 'parametro' }],
1281
+ ['restrictions', { noun: 'restrizione', preposition: 'su' }],
1282
+ ['artifactPlan', { noun: 'piano dell’artefatto', preposition: 'di' }],
1283
+ ]);
1284
+ function dpeSegmentLabel(segment) {
1285
+ const index = segment.index === undefined ? '' : `[${segment.index}]`;
1286
+ return `${segment.collection ?? ''}${segment.name ? `/${segment.name}` : index}`;
1287
+ }
1288
+ /**
1289
+ * La radice non-nodo descritta: col nome se c'e', altrimenti con l'indice se c'e', altrimenti con
1290
+ * la sola parola. Nessuna delle tre strade restituisce vuoto per una radice conosciuta, ed e' il
1291
+ * punto: il nome vuoto e l'indice senza nome sono proprio le forme che si scartavano.
1292
+ */
1293
+ function dpeNonNodeRootLabel(segment) {
1294
+ const words = NON_NODE_ROOT_WORDS.get(segment.collection ?? '');
1295
+ if (words === undefined) {
1296
+ return dpeSegmentLabel(segment);
1297
+ }
1298
+ if (segment.name) {
1299
+ return [words.noun, words.preposition, segment.name].filter(Boolean).join(' ');
1300
+ }
1301
+ return segment.index === undefined ? words.noun : `${words.noun} [${segment.index}]`;
1302
+ }
1251
1303
  /** Testo leggibile del percorso, per la riga del pannello. */
1252
1304
  function dpeDiagnosticLocationLabel(diagnostic, definition) {
1253
1305
  const node = dpeDiagnosticNodeName(diagnostic, definition);
1254
- const segments = diagnostic.path?.segments ?? [];
1255
- const tail = segments
1256
- .slice(1)
1257
- .map((segment) => {
1258
- const index = segment.index === undefined ? '' : `[${segment.index}]`;
1259
- return `${segment.collection ?? ''}${segment.name ? `/${segment.name}` : index}`;
1260
- })
1261
- .filter((part) => part.length > 0);
1306
+ const [first, ...rest] = diagnostic.path?.segments ?? [];
1307
+ /*
1308
+ * Il primo segmento si scartava sempre, perche' si presumeva che fosse il nodo e il nodo e' gia'
1309
+ * in testa. Da quando `parameters`, `restrictions` e `artifactPlan` non indicano un nodo,
1310
+ * scartarlo cancellava **quale** parametro o writeback: il messaggio di
1311
+ * `DPE_MODEL_CONDITIONAL_REQUIRED` non lo nomina, e due parametri senza `valueType` davano due
1312
+ * righe identiche, `definizione › valueType`. Lo stesso controllo di `dpeDiagnosticNodeName`
1313
+ * decide qui, cosi' il primo segmento e' o il nodo in testa o la radice descritta, mai tutt'e due
1314
+ * e mai nessuno.
1315
+ *
1316
+ * Il controllo e' sulla sola radice, non sulla presenza del nome: la deserializzazione non
1317
+ * conosce i nomi (`parameters[0].valueType`), la validazione non ne ha uno per un parametro che
1318
+ * non lo porta, e `ArtifactPlanValidator` nomina il piano con `""` quando manca proprio il
1319
+ * `writebackName` di cui si lamenta — tre forme in cui scartare il segmento attribuiva il difetto
1320
+ * alla definizione. La riga resta non navigabile: lo decide `dpeDiagnosticNodeName`, non questa
1321
+ * etichetta.
1322
+ */
1323
+ const root = first && !dpeIsNodeCollectionName(first.collection) ? dpeNonNodeRootLabel(first) : '';
1324
+ const head = root.length === 0 ? [node ?? 'definizione'] : [node, root];
1325
+ const tail = rest.map(dpeSegmentLabel).filter((part) => part.length > 0);
1262
1326
  const field = diagnostic.path?.field;
1263
- return [node ?? 'definizione', ...tail, field].filter(Boolean).join(' › ');
1327
+ return [...head, ...tail, field].filter(Boolean).join(' › ');
1264
1328
  }
1265
1329
  /** I nomi dei nodi presenti nella definizione: serve a chi naviga dal pannello al canvas. */
1266
1330
  function dpeKnownNodeNames(definition) {