@elisra-devops/docgen-data-provider 1.104.0 → 1.106.0

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.
@@ -27,6 +27,10 @@ type DocTypeBranchConfig = {
27
27
  fallbackStart?: any;
28
28
  };
29
29
 
30
+ /** Default fields fetched per work item in tree/flat query parsing. */
31
+ const WI_DEFAULT_FIELDS =
32
+ 'System.Description,System.Title,Microsoft.VSTS.TCM.ReproSteps,Microsoft.VSTS.CMMI.Symptom';
33
+
30
34
  export default class TicketsDataProvider {
31
35
  orgUrl: string = '';
32
36
  token: string = '';
@@ -199,12 +203,24 @@ export default class TicketsDataProvider {
199
203
  const queriesWithChildren = await this.ensureQueryChildren(queries);
200
204
 
201
205
  switch (normalizedDocType) {
202
- case 'std': {
203
- const { root: stdRoot, found: stdRootFound } = await this.getDocTypeRoot(
204
- queriesWithChildren,
205
- 'std'
206
+ case 'std':
207
+ case 'stp': {
208
+ const rootCandidates = normalizedDocType === 'stp' ? (['stp', 'std'] as const) : (['std'] as const);
209
+ let stdRoot = queriesWithChildren;
210
+ let stdRootFound = false;
211
+ for (const candidate of rootCandidates) {
212
+ const lookup = await this.getDocTypeRoot(queriesWithChildren, candidate);
213
+ if (lookup.found) {
214
+ stdRoot = lookup.root;
215
+ stdRootFound = true;
216
+ break;
217
+ }
218
+ }
219
+ logger.debug(
220
+ `[GetSharedQueries][${normalizedDocType}] using ${
221
+ stdRootFound ? 'dedicated folder' : 'root queries'
222
+ }`,
206
223
  );
207
- logger.debug(`[GetSharedQueries][std] using ${stdRootFound ? 'dedicated folder' : 'root queries'}`);
208
224
  // Each branch describes the dedicated folder names, the fetch routine, and how to validate results.
209
225
  const stdBranches = await this.fetchDocTypeBranches(queriesWithChildren, stdRoot, [
210
226
  {
@@ -258,7 +274,7 @@ export default class TicketsDataProvider {
258
274
  case 'str': {
259
275
  const { root: strRoot, found: strRootFound } = await this.getDocTypeRoot(
260
276
  queriesWithChildren,
261
- 'str'
277
+ 'str',
262
278
  );
263
279
  logger.debug(`[GetSharedQueries][str] using ${strRootFound ? 'dedicated folder' : 'root queries'}`);
264
280
  const strBranches = await this.fetchDocTypeBranches(queriesWithChildren, strRoot, [
@@ -325,12 +341,12 @@ export default class TicketsDataProvider {
325
341
  case 'test-reporter': {
326
342
  const { root: testReporterRoot, found: testReporterFound } = await this.getDocTypeRoot(
327
343
  queriesWithChildren,
328
- 'test-reporter'
344
+ 'test-reporter',
329
345
  );
330
346
  logger.debug(
331
347
  `[GetSharedQueries][test-reporter] using ${
332
348
  testReporterFound ? 'dedicated folder' : 'root queries'
333
- }`
349
+ }`,
334
350
  );
335
351
  const testReporterBranches = await this.fetchDocTypeBranches(
336
352
  queriesWithChildren,
@@ -343,13 +359,15 @@ export default class TicketsDataProvider {
343
359
  fetcher: (folder: any) => this.fetchTestReporterQueries(folder),
344
360
  validator: (result: any) => this.hasAnyQueryTree(result?.testAssociatedTree),
345
361
  },
346
- ]
362
+ ],
347
363
  );
348
364
  const testReporterFetch = testReporterBranches['testReporter'];
349
365
  return testReporterFetch?.result ?? { testAssociatedTree: null };
350
366
  }
351
367
  case 'srs':
352
368
  return await this.fetchSrsQueries(queriesWithChildren);
369
+ case 'sysrs':
370
+ return await this.fetchSysRsQueries(queriesWithChildren);
353
371
  case 'svd': {
354
372
  const { root: svdRoot, found } = await this.getDocTypeRoot(queriesWithChildren, 'svd');
355
373
  if (!found) {
@@ -416,7 +434,7 @@ export default class TicketsDataProvider {
416
434
  field.name !== 'Title' &&
417
435
  field.name !== 'Description' &&
418
436
  field.name !== 'Work Item Type' &&
419
- field.name !== 'Steps'
437
+ field.name !== 'Steps',
420
438
  )
421
439
  .map((field: any) => {
422
440
  return {
@@ -443,7 +461,7 @@ export default class TicketsDataProvider {
443
461
  onlyTestReq,
444
462
  null,
445
463
  ['Requirement'],
446
- ['Test Case']
464
+ ['Test Case'],
447
465
  );
448
466
  return { reqTestTree, testReqTree };
449
467
  }
@@ -476,7 +494,7 @@ export default class TicketsDataProvider {
476
494
  'Review',
477
495
  'Test Plan',
478
496
  'Test Suite',
479
- ]
497
+ ],
480
498
  );
481
499
  return { linkedMomTree };
482
500
  }
@@ -532,7 +550,7 @@ export default class TicketsDataProvider {
532
550
  onlySourceSide,
533
551
  null,
534
552
  ['Bug', 'Change Request'],
535
- ['Test Case']
553
+ ['Test Case'],
536
554
  );
537
555
  return { OpenPcrToTestTree, TestToOpenPcrTree };
538
556
  }
@@ -548,7 +566,7 @@ export default class TicketsDataProvider {
548
566
  true,
549
567
  null,
550
568
  ['Requirement', 'Bug', 'Change Request'],
551
- ['Test Case']
569
+ ['Test Case'],
552
570
  );
553
571
  return { testAssociatedTree };
554
572
  }
@@ -578,7 +596,7 @@ export default class TicketsDataProvider {
578
596
  undefined,
579
597
  true, // Enable processing of both tree and direct link queries, including flat queries
580
598
  excludedFolderNames,
581
- true
599
+ true,
582
600
  );
583
601
  return { systemRequirementsQueryTree };
584
602
  }
@@ -604,19 +622,17 @@ export default class TicketsDataProvider {
604
622
 
605
623
  const systemToSoftwareFolder = await this.findChildFolderByName(
606
624
  srsFolderWithChildren,
607
- 'System to Software'
625
+ 'System to Software',
608
626
  );
609
627
  const softwareToSystemFolder = await this.findChildFolderByName(
610
628
  srsFolderWithChildren,
611
- 'Software to System'
629
+ 'Software to System',
612
630
  );
613
631
 
614
- const systemToSoftwareRequirementsQueries = await this.fetchRequirementsTraceQueriesForFolder(
615
- systemToSoftwareFolder
616
- );
617
- const softwareToSystemRequirementsQueries = await this.fetchRequirementsTraceQueriesForFolder(
618
- softwareToSystemFolder
619
- );
632
+ const systemToSoftwareRequirementsQueries =
633
+ await this.fetchRequirementsTraceQueriesForFolder(systemToSoftwareFolder);
634
+ const softwareToSystemRequirementsQueries =
635
+ await this.fetchRequirementsTraceQueriesForFolder(softwareToSystemFolder);
620
636
 
621
637
  return {
622
638
  systemRequirementsQueries,
@@ -625,6 +641,40 @@ export default class TicketsDataProvider {
625
641
  };
626
642
  }
627
643
 
644
+ private async fetchSysRsQueries(rootQueries: any) {
645
+ const { root: sysRsRoot, found: sysRsRootFound } = await this.getDocTypeRoot(rootQueries, 'sysrs');
646
+ logger.debug(`[GetSharedQueries][sysrs] using ${sysRsRootFound ? 'dedicated folder' : 'root queries'}`);
647
+
648
+ const systemRequirementsQueries = await this.fetchSystemRequirementQueries(sysRsRoot, [
649
+ 'System To Customer',
650
+ 'System To Subsystem',
651
+ ]);
652
+
653
+ const systemToCustomerFolder = await this.findChildFolderByPossibleNames(sysRsRoot, [
654
+ 'system to customer',
655
+ 'system-to-customer',
656
+ 'system customer',
657
+ 'subsystem to system',
658
+ 'customer to system',
659
+ ]);
660
+ const systemToSubsystemFolder = await this.findChildFolderByPossibleNames(sysRsRoot, [
661
+ 'system to subsystem',
662
+ 'system-to-subsystem',
663
+ 'system subsystem',
664
+ ]);
665
+
666
+ const subsystemToSystemRequirementsQueries =
667
+ await this.fetchRequirementsTraceQueriesForFolder(systemToCustomerFolder);
668
+ const systemToSubsystemRequirementsQueries =
669
+ await this.fetchRequirementsTraceQueriesForFolder(systemToSubsystemFolder);
670
+
671
+ return {
672
+ systemRequirementsQueries,
673
+ subsystemToSystemRequirementsQueries,
674
+ systemToSubsystemRequirementsQueries,
675
+ };
676
+ }
677
+
628
678
  /**
629
679
  * Fetches and structures linked queries related to requirements traceability with area path filtering.
630
680
  *
@@ -649,7 +699,7 @@ export default class TicketsDataProvider {
649
699
  ['epic', 'feature', 'requirement'],
650
700
  ['epic', 'feature', 'requirement'],
651
701
  'sys', // Source area filter for tree1: System area paths
652
- 'soft' // Target area filter for tree1: Software area paths (tree2 will be reversed automatically)
702
+ 'soft', // Target area filter for tree1: Software area paths (tree2 will be reversed automatically)
653
703
  );
654
704
  return { SystemToSoftwareRequirementsTree, SoftwareToSystemRequirementsTree };
655
705
  }
@@ -667,7 +717,7 @@ export default class TicketsDataProvider {
667
717
  ['epic', 'feature', 'requirement'],
668
718
  undefined,
669
719
  undefined,
670
- true
720
+ true,
671
721
  );
672
722
  return tree1;
673
723
  }
@@ -714,7 +764,7 @@ export default class TicketsDataProvider {
714
764
  const normalizedName = childName.toLowerCase();
715
765
  return (
716
766
  parentWithChildren.children.find(
717
- (child: any) => child.isFolder && (child.name || '').toLowerCase() === normalizedName
767
+ (child: any) => child.isFolder && (child.name || '').toLowerCase() === normalizedName,
718
768
  ) || null
719
769
  );
720
770
  }
@@ -823,7 +873,7 @@ export default class TicketsDataProvider {
823
873
  startingFolder: any,
824
874
  fetcher: (folder: any) => Promise<any>,
825
875
  logContext: string,
826
- validator?: (result: any) => boolean
876
+ validator?: (result: any) => boolean,
827
877
  ): Promise<{ result: any; usedFolder: any }> {
828
878
  const rootWithChildren = await this.ensureQueryChildren(rootQueries);
829
879
  const candidates = await this.buildFallbackChain(rootWithChildren, startingFolder);
@@ -857,7 +907,7 @@ export default class TicketsDataProvider {
857
907
  private async fetchDocTypeBranches(
858
908
  queriesWithChildren: any,
859
909
  docRoot: any,
860
- branches: DocTypeBranchConfig[]
910
+ branches: DocTypeBranchConfig[],
861
911
  ): Promise<Record<string, FallbackFetchOutcome>> {
862
912
  const results: Record<string, FallbackFetchOutcome> = {};
863
913
  const effectiveDocRoot = docRoot ?? queriesWithChildren;
@@ -871,7 +921,7 @@ export default class TicketsDataProvider {
871
921
  if (branch.folderNames?.length && effectiveDocRoot) {
872
922
  const resolvedFolder = await this.findChildFolderByPossibleNames(
873
923
  effectiveDocRoot,
874
- branch.folderNames
924
+ branch.folderNames,
875
925
  );
876
926
  if (resolvedFolder) {
877
927
  startingFolder = resolvedFolder;
@@ -886,7 +936,7 @@ export default class TicketsDataProvider {
886
936
  startingFolder,
887
937
  branch.fetcher,
888
938
  branch.label,
889
- branch.validator
939
+ branch.validator,
890
940
  );
891
941
 
892
942
  logger.debug(`${branch.label} final folder: ${fetchOutcome.usedFolder?.name ?? '<root>'}`);
@@ -942,7 +992,7 @@ export default class TicketsDataProvider {
942
992
  private async findPathToNode(
943
993
  currentNode: any,
944
994
  targetId: string,
945
- visited: Set<string> = new Set<string>()
995
+ visited: Set<string> = new Set<string>(),
946
996
  ): Promise<any[] | null> {
947
997
  if (!currentNode) {
948
998
  return null;
@@ -976,7 +1026,7 @@ export default class TicketsDataProvider {
976
1026
 
977
1027
  private async getDocTypeRoot(
978
1028
  rootQueries: any,
979
- docTypeName: string
1029
+ docTypeName: string,
980
1030
  ): Promise<{ root: any; found: boolean }> {
981
1031
  if (!rootQueries) {
982
1032
  return { root: rootQueries, found: false };
@@ -1009,7 +1059,8 @@ export default class TicketsDataProvider {
1009
1059
  async GetQueryResultsFromWiql(
1010
1060
  wiqlHref: string = '',
1011
1061
  displayAsTable: boolean = false,
1012
- testCaseToRelatedWiMap: Map<number, Set<any>>
1062
+ testCaseToRelatedWiMap: Map<number, Set<any>>,
1063
+ fetchAllFields: boolean = false,
1013
1064
  ): Promise<any> {
1014
1065
  try {
1015
1066
  if (!wiqlHref) {
@@ -1025,13 +1076,13 @@ export default class TicketsDataProvider {
1025
1076
  case QueryType.OneHop:
1026
1077
  return displayAsTable
1027
1078
  ? await this.parseDirectLinkedQueryResultForTableFormat(queryResult, testCaseToRelatedWiMap)
1028
- : await this.parseTreeQueryResult(queryResult);
1079
+ : await this.parseTreeQueryResult(queryResult, fetchAllFields);
1029
1080
  case QueryType.Tree:
1030
- return await this.parseTreeQueryResult(queryResult);
1081
+ return await this.parseTreeQueryResult(queryResult, fetchAllFields);
1031
1082
  case QueryType.Flat:
1032
1083
  return displayAsTable
1033
1084
  ? await this.parseFlatQueryResultForTableFormat(queryResult)
1034
- : await this.parseFlatQueryResult(queryResult);
1085
+ : await this.parseFlatQueryResult(queryResult, fetchAllFields);
1035
1086
  default:
1036
1087
  break;
1037
1088
  }
@@ -1042,7 +1093,7 @@ export default class TicketsDataProvider {
1042
1093
 
1043
1094
  private async parseDirectLinkedQueryResultForTableFormat(
1044
1095
  queryResult: QueryTree,
1045
- testCaseToRelatedWiMap: Map<number, Set<any>>
1096
+ testCaseToRelatedWiMap: Map<number, Set<any>>,
1046
1097
  ) {
1047
1098
  const { columns, workItemRelations } = queryResult;
1048
1099
 
@@ -1091,17 +1142,17 @@ export default class TicketsDataProvider {
1091
1142
  const allSourcePromises = Array.from(sourceIds).map((id) =>
1092
1143
  this.limit(() => {
1093
1144
  const relation = workItemRelations.find(
1094
- (r) => (!r.source && r.target.id === id) || r.source?.id === id
1145
+ (r) => (!r.source && r.target.id === id) || r.source?.id === id,
1095
1146
  );
1096
1147
  return this.fetchWIForQueryResult(relation, columnsToShowMap, columnSourceMap, true);
1097
- })
1148
+ }),
1098
1149
  );
1099
1150
 
1100
1151
  const allTargetPromises = Array.from(targetIds).map((id) =>
1101
1152
  this.limit(() => {
1102
1153
  const relation = workItemRelations.find((r) => r.target?.id === id);
1103
1154
  return this.fetchWIForQueryResult(relation, columnsToShowMap, columnTargetsMap, true);
1104
- })
1155
+ }),
1105
1156
  );
1106
1157
 
1107
1158
  // Wait for all fetches to complete in parallel (with concurrency control)
@@ -1175,7 +1226,7 @@ export default class TicketsDataProvider {
1175
1226
  private mapTestCaseToRelatedItem(
1176
1227
  sourceWi: any,
1177
1228
  targetWi: any,
1178
- testCaseToRelatedItemMap: Map<number, Set<any>>
1229
+ testCaseToRelatedItemMap: Map<number, Set<any>>,
1179
1230
  ) {
1180
1231
  if (sourceWi.fields['System.WorkItemType'] == 'Test Case') {
1181
1232
  if (!testCaseToRelatedItemMap.has(sourceWi.id)) {
@@ -1217,7 +1268,7 @@ export default class TicketsDataProvider {
1217
1268
  const wiSet: Set<any> = new Set();
1218
1269
  if (workItems) {
1219
1270
  const fetchPromises = workItems.map((workItem) =>
1220
- this.limit(() => this.fetchWIForQueryResult(workItem, columnsToShowMap, fieldsToIncludeMap, false))
1271
+ this.limit(() => this.fetchWIForQueryResult(workItem, columnsToShowMap, fieldsToIncludeMap, false)),
1221
1272
  );
1222
1273
 
1223
1274
  const fetchedWorkItems = await Promise.all(fetchPromises);
@@ -1231,7 +1282,7 @@ export default class TicketsDataProvider {
1231
1282
  };
1232
1283
  }
1233
1284
 
1234
- private async parseTreeQueryResult(queryResult: QueryTree) {
1285
+ private async parseTreeQueryResult(queryResult: QueryTree, fetchAllFields: boolean = false) {
1235
1286
  const { workItemRelations } = queryResult;
1236
1287
  if (!workItemRelations) return null;
1237
1288
 
@@ -1245,11 +1296,11 @@ export default class TicketsDataProvider {
1245
1296
  // This ensures nodes with non-hierarchy links are also available
1246
1297
  for (const rel of workItemRelations) {
1247
1298
  const t = rel.target;
1248
- if (!allItems[t.id]) await this.initTreeQueryResultItem(t, allItems);
1299
+ if (!allItems[t.id]) await this.initTreeQueryResultItem(t, allItems, fetchAllFields);
1249
1300
 
1250
1301
  // Also initialize source nodes if they exist
1251
1302
  if (rel.source && !allItems[rel.source.id]) {
1252
- await this.initTreeQueryResultItem(rel.source, allItems);
1303
+ await this.initTreeQueryResultItem(rel.source, allItems, fetchAllFields);
1253
1304
  }
1254
1305
 
1255
1306
  if (rel.rel === null && rel.source === null) {
@@ -1260,7 +1311,7 @@ export default class TicketsDataProvider {
1260
1311
  }
1261
1312
  }
1262
1313
  logger.debug(
1263
- `parseTreeQueryResult: Found ${rootOrder.length} roots, ${Object.keys(allItems).length} total nodes`
1314
+ `parseTreeQueryResult: Found ${rootOrder.length} roots, ${Object.keys(allItems).length} total nodes`,
1264
1315
  );
1265
1316
 
1266
1317
  // Attach only forward hierarchy edges; dedupe children by id per parent
@@ -1280,11 +1331,11 @@ export default class TicketsDataProvider {
1280
1331
  // Nodes should already be initialized, but double-check
1281
1332
  if (!allItems[parentId]) {
1282
1333
  logger.warn(`Parent ${parentId} not found, initializing now`);
1283
- await this.initTreeQueryResultItem(rel.source, allItems);
1334
+ await this.initTreeQueryResultItem(rel.source, allItems, fetchAllFields);
1284
1335
  }
1285
1336
  if (!allItems[childId]) {
1286
1337
  logger.warn(`Child ${childId} not found, initializing now`);
1287
- await this.initTreeQueryResultItem(rel.target, allItems);
1338
+ await this.initTreeQueryResultItem(rel.target, allItems, fetchAllFields);
1288
1339
  }
1289
1340
 
1290
1341
  const parent = allItems[parentId];
@@ -1300,13 +1351,13 @@ export default class TicketsDataProvider {
1300
1351
  }
1301
1352
  }
1302
1353
  logger.debug(
1303
- `parseTreeQueryResult: ${hierarchyCount} hierarchy links, ${skippedNonHierarchy} non-hierarchy links skipped`
1354
+ `parseTreeQueryResult: ${hierarchyCount} hierarchy links, ${skippedNonHierarchy} non-hierarchy links skipped`,
1304
1355
  );
1305
1356
 
1306
1357
  // Return roots in original order, excluding those that became children
1307
1358
  const roots = rootOrder.filter((id) => rootSet.has(id)).map((id) => allItems[id]);
1308
1359
  logger.debug(
1309
- `parseTreeQueryResult: Returning ${roots.length} roots with ${Object.keys(allItems).length} total items`
1360
+ `parseTreeQueryResult: Returning ${roots.length} roots with ${Object.keys(allItems).length} total items`,
1310
1361
  );
1311
1362
 
1312
1363
  // Optional: clean helper sets
@@ -1319,32 +1370,42 @@ export default class TicketsDataProvider {
1319
1370
  };
1320
1371
  }
1321
1372
 
1322
- private async initTreeQueryResultItem(item: any, allItems: any) {
1323
- const urlWi = `${item.url}?fields=System.Description,System.Title,Microsoft.VSTS.TCM.ReproSteps,Microsoft.VSTS.CMMI.Symptom`;
1373
+ private async initTreeQueryResultItem(item: any, allItems: any, fetchAllFields: boolean = false) {
1374
+ const urlWi = fetchAllFields ? `${item.url}` : `${item.url}?fields=${WI_DEFAULT_FIELDS}`;
1324
1375
  const wi = await TFSServices.getItemContent(urlWi, this.token);
1376
+ const fields = wi?.fields || {};
1325
1377
  // need to fetch the WI with only the the title, the web URL and the description
1326
1378
  allItems[item.id] = {
1327
1379
  id: item.id,
1328
- title: wi.fields['System.Title'] || '',
1329
- description: wi.fields['Microsoft.VSTS.CMMI.Symptom'] ?? wi.fields['System.Description'] ?? '',
1380
+ title: fields['System.Title'] || '',
1381
+ description: fields['Microsoft.VSTS.CMMI.Symptom'] ?? fields['System.Description'] ?? '',
1330
1382
  htmlUrl: wi._links.html.href,
1383
+ fields,
1384
+ workItemType: fields['System.WorkItemType'] || '',
1331
1385
  children: [],
1332
1386
  };
1333
1387
  }
1334
1388
 
1335
- private async initFlatQueryResultItem(item: any, workItemMap: Map<number, any>) {
1336
- const urlWi = `${item.url}?fields=System.Description,System.Title,Microsoft.VSTS.TCM.ReproSteps,Microsoft.VSTS.CMMI.Symptom`;
1389
+ private async initFlatQueryResultItem(
1390
+ item: any,
1391
+ workItemMap: Map<number, any>,
1392
+ fetchAllFields: boolean = false,
1393
+ ) {
1394
+ const urlWi = fetchAllFields ? `${item.url}` : `${item.url}?fields=${WI_DEFAULT_FIELDS}`;
1337
1395
  const wi = await TFSServices.getItemContent(urlWi, this.token);
1396
+ const fields = wi?.fields || {};
1338
1397
  // need to fetch the WI with only the the title, the web URL and the description
1339
1398
  workItemMap.set(item.id, {
1340
1399
  id: item.id,
1341
- title: wi.fields['System.Title'] || '',
1342
- description: wi.fields['Microsoft.VSTS.CMMI.Symptom'] ?? wi.fields['System.Description'] ?? '',
1400
+ title: fields['System.Title'] || '',
1401
+ description: fields['Microsoft.VSTS.CMMI.Symptom'] ?? fields['System.Description'] ?? '',
1343
1402
  htmlUrl: wi._links.html.href,
1403
+ fields,
1404
+ workItemType: fields['System.WorkItemType'] || '',
1344
1405
  });
1345
1406
  }
1346
1407
 
1347
- private async parseFlatQueryResult(queryResult: QueryTree) {
1408
+ private async parseFlatQueryResult(queryResult: QueryTree, fetchAllFields: boolean = false) {
1348
1409
  const { workItems } = queryResult;
1349
1410
  if (!workItems) {
1350
1411
  logger.warn(`No work items were found for this requested query`);
@@ -1355,7 +1416,7 @@ export default class TicketsDataProvider {
1355
1416
  const workItemsResultMap: Map<number, any> = new Map();
1356
1417
  for (const wi of workItems) {
1357
1418
  if (!workItemsResultMap.has(wi.id)) {
1358
- await this.initFlatQueryResultItem(wi, workItemsResultMap);
1419
+ await this.initFlatQueryResultItem(wi, workItemsResultMap, fetchAllFields);
1359
1420
  }
1360
1421
  }
1361
1422
  return [...workItemsResultMap.values()];
@@ -1368,7 +1429,7 @@ export default class TicketsDataProvider {
1368
1429
  receivedObject: any,
1369
1430
  columnMap: Map<string, string>,
1370
1431
  resultedRefNameMap: Map<string, string>,
1371
- isRelation: boolean
1432
+ isRelation: boolean,
1372
1433
  ) {
1373
1434
  const url = isRelation ? `${receivedObject.target.url}` : `${receivedObject.url}`;
1374
1435
  const wi: any = await TFSServices.getItemContent(url, this.token);
@@ -1401,7 +1462,7 @@ export default class TicketsDataProvider {
1401
1462
  if (modeledResult.queryType == 'tree') {
1402
1463
  let levelResults: Array<Workitem> = Helper.LevelBuilder(
1403
1464
  modeledResult,
1404
- modeledResult.workItems[0].fields[0].value
1465
+ modeledResult.workItems[0].fields[0].value,
1405
1466
  );
1406
1467
  return levelResults;
1407
1468
  }
@@ -1572,7 +1633,7 @@ export default class TicketsDataProvider {
1572
1633
 
1573
1634
  async CreateNewWorkItem(projectName: string, wiBody: any, wiType: string, byPass: boolean) {
1574
1635
  let url = `${this.orgUrl}${projectName}/_apis/wit/workitems/$${wiType}?bypassRules=${String(
1575
- byPass
1636
+ byPass,
1576
1637
  ).toString()}`;
1577
1638
  return TFSServices.getItemContent(url, this.token, 'POST', wiBody, {
1578
1639
  'Content-Type': 'application/json-patch+json',
@@ -1592,7 +1653,7 @@ export default class TicketsDataProvider {
1592
1653
  attachment.downloadUrl = `${relation.url}/${relation.attributes.name}`;
1593
1654
  attachmentList.push(attachment);
1594
1655
  }
1595
- })
1656
+ }),
1596
1657
  );
1597
1658
  return attachmentList;
1598
1659
  } catch (e) {
@@ -1613,7 +1674,7 @@ export default class TicketsDataProvider {
1613
1674
  async UpdateWorkItem(projectName: string, wiBody: any, workItemId: number, byPass: boolean) {
1614
1675
  let res: any;
1615
1676
  let url: string = `${this.orgUrl}${projectName}/_apis/wit/workitems/${workItemId}?bypassRules=${String(
1616
- byPass
1677
+ byPass,
1617
1678
  ).toString()}`;
1618
1679
  res = await TFSServices.getItemContent(url, this.token, 'patch', wiBody, {
1619
1680
  'Content-Type': 'application/json-patch+json',
@@ -1667,7 +1728,7 @@ export default class TicketsDataProvider {
1667
1728
 
1668
1729
  // Process children recursively
1669
1730
  const childResults = await Promise.all(
1670
- rootQuery.children.map((child: any) => this.structureAllQueryPath(child, rootQuery.id))
1731
+ rootQuery.children.map((child: any) => this.structureAllQueryPath(child, rootQuery.id)),
1671
1732
  );
1672
1733
 
1673
1734
  // Build tree
@@ -1705,8 +1766,8 @@ export default class TicketsDataProvider {
1705
1766
  } catch (err: any) {
1706
1767
  logger.error(
1707
1768
  `Error occurred while constructing the query list ${err.message} with query ${JSON.stringify(
1708
- rootQuery
1709
- )}`
1769
+ rootQuery,
1770
+ )}`,
1710
1771
  );
1711
1772
  throw err;
1712
1773
  }
@@ -1744,7 +1805,7 @@ export default class TicketsDataProvider {
1744
1805
  includeTreeQueries: boolean = false,
1745
1806
  excludedFolderNames: string[] = [],
1746
1807
  includeFlatQueries: boolean = false,
1747
- workItemTypeCache?: Map<string, string | null>
1808
+ workItemTypeCache?: Map<string, string | null>,
1748
1809
  ): Promise<any> {
1749
1810
  try {
1750
1811
  // Per-invocation cache for ID->WorkItemType lookups; avoids global state and is safe for concurrency.
@@ -1752,7 +1813,7 @@ export default class TicketsDataProvider {
1752
1813
  const shouldSkipFolder =
1753
1814
  rootQuery?.isFolder &&
1754
1815
  excludedFolderNames.some(
1755
- (folderName) => folderName.toLowerCase() === (rootQuery.name || '').toLowerCase()
1816
+ (folderName) => folderName.toLowerCase() === (rootQuery.name || '').toLowerCase(),
1756
1817
  );
1757
1818
 
1758
1819
  if (shouldSkipFolder) {
@@ -1776,7 +1837,7 @@ export default class TicketsDataProvider {
1776
1837
  rootQuery,
1777
1838
  wiql,
1778
1839
  allTypes,
1779
- typeCache
1840
+ typeCache,
1780
1841
  );
1781
1842
 
1782
1843
  if (typesOk) {
@@ -1803,7 +1864,7 @@ export default class TicketsDataProvider {
1803
1864
  wiql,
1804
1865
  sources,
1805
1866
  targets,
1806
- typeCache
1867
+ typeCache,
1807
1868
  );
1808
1869
  }
1809
1870
  const matchesReverse = await this.matchesSourceTargetConditionAsync(
@@ -1811,7 +1872,7 @@ export default class TicketsDataProvider {
1811
1872
  wiql,
1812
1873
  targets,
1813
1874
  sources,
1814
- typeCache
1875
+ typeCache,
1815
1876
  );
1816
1877
 
1817
1878
  if (matchesForward) {
@@ -1858,7 +1919,7 @@ export default class TicketsDataProvider {
1858
1919
  includeTreeQueries,
1859
1920
  excludedFolderNames,
1860
1921
  includeFlatQueries,
1861
- typeCache
1922
+ typeCache,
1862
1923
  );
1863
1924
  }
1864
1925
 
@@ -1876,9 +1937,9 @@ export default class TicketsDataProvider {
1876
1937
  includeTreeQueries,
1877
1938
  excludedFolderNames,
1878
1939
  includeFlatQueries,
1879
- typeCache
1880
- )
1881
- )
1940
+ typeCache,
1941
+ ),
1942
+ ),
1882
1943
  );
1883
1944
 
1884
1945
  // Build tree1
@@ -1911,8 +1972,8 @@ export default class TicketsDataProvider {
1911
1972
  } catch (err: any) {
1912
1973
  logger.error(
1913
1974
  `Error occurred while constructing the query list ${err.message} with query ${JSON.stringify(
1914
- rootQuery
1915
- )}`
1975
+ rootQuery,
1976
+ )}`,
1916
1977
  );
1917
1978
  logger.error(`Error stack ${err.message}`);
1918
1979
  }
@@ -1928,7 +1989,7 @@ export default class TicketsDataProvider {
1928
1989
  private matchesAreaPathCondition(
1929
1990
  wiql: string,
1930
1991
  sourceAreaFilter: string,
1931
- targetAreaFilter: string
1992
+ targetAreaFilter: string,
1932
1993
  ): boolean {
1933
1994
  const wiqlLower = (wiql || '').toLowerCase();
1934
1995
  const srcFilter = (sourceAreaFilter || '').toLowerCase().trim();
@@ -1966,7 +2027,7 @@ export default class TicketsDataProvider {
1966
2027
  wiql: string,
1967
2028
  source: string[],
1968
2029
  target: string[],
1969
- workItemTypeCache: Map<string, string | null>
2030
+ workItemTypeCache: Map<string, string | null>,
1970
2031
  ): Promise<boolean> {
1971
2032
  /**
1972
2033
  * Matches source+target constraints for link WIQL.
@@ -1979,7 +2040,7 @@ export default class TicketsDataProvider {
1979
2040
  wiql,
1980
2041
  'Source',
1981
2042
  source,
1982
- workItemTypeCache
2043
+ workItemTypeCache,
1983
2044
  );
1984
2045
  if (!sourceOk) return false;
1985
2046
  const targetOk = await this.isLinkSideAllowedByTypeOrId(
@@ -1987,7 +2048,7 @@ export default class TicketsDataProvider {
1987
2048
  wiql,
1988
2049
  'Target',
1989
2050
  target,
1990
- workItemTypeCache
2051
+ workItemTypeCache,
1991
2052
  );
1992
2053
  return targetOk;
1993
2054
  }
@@ -1996,7 +2057,7 @@ export default class TicketsDataProvider {
1996
2057
  queryNode: any,
1997
2058
  wiql: string,
1998
2059
  allowedTypes: string[],
1999
- workItemTypeCache: Map<string, string | null>
2060
+ workItemTypeCache: Map<string, string | null>,
2000
2061
  ): Promise<boolean> {
2001
2062
  return this.isFlatQueryAllowedByTypeOrId(queryNode, wiql, allowedTypes, workItemTypeCache);
2002
2063
  }
@@ -2136,7 +2197,7 @@ export default class TicketsDataProvider {
2136
2197
  wiql: string,
2137
2198
  context: 'Source' | 'Target',
2138
2199
  allowedTypes: string[],
2139
- workItemTypeCache: Map<string, string | null>
2200
+ workItemTypeCache: Map<string, string | null>,
2140
2201
  ): Promise<boolean> {
2141
2202
  const wiqlStr = String(wiql || '');
2142
2203
 
@@ -2144,7 +2205,7 @@ export default class TicketsDataProvider {
2144
2205
  if (!allowedTypes || allowedTypes.length === 0) {
2145
2206
  const fieldPresenceRegex = new RegExp(
2146
2207
  `${this.buildWiqlFieldPattern(context, 'System.WorkItemType')}`,
2147
- 'i'
2208
+ 'i',
2148
2209
  );
2149
2210
  return fieldPresenceRegex.test(wiqlStr);
2150
2211
  }
@@ -2184,7 +2245,7 @@ export default class TicketsDataProvider {
2184
2245
  queryNode: any,
2185
2246
  wiql: string,
2186
2247
  allowedTypes: string[],
2187
- workItemTypeCache: Map<string, string | null>
2248
+ workItemTypeCache: Map<string, string | null>,
2188
2249
  ): Promise<boolean> {
2189
2250
  const wiqlStr = String(wiql || '');
2190
2251
 
@@ -2227,7 +2288,7 @@ export default class TicketsDataProvider {
2227
2288
  private async getWorkItemTypeById(
2228
2289
  project: string,
2229
2290
  id: string,
2230
- workItemTypeCache: Map<string, string | null>
2291
+ workItemTypeCache: Map<string, string | null>,
2231
2292
  ): Promise<string | null> {
2232
2293
  const cacheKey = `${project}:${id}`;
2233
2294
  if (workItemTypeCache.has(cacheKey)) {
@@ -2285,7 +2346,7 @@ export default class TicketsDataProvider {
2285
2346
  private filterFieldsByColumns(
2286
2347
  item: any,
2287
2348
  columnsToFilterMap: Map<string, string>,
2288
- resultedRefNameMap: Map<string, string>
2349
+ resultedRefNameMap: Map<string, string>,
2289
2350
  ) {
2290
2351
  try {
2291
2352
  const parsedFields: any = {};
@@ -2332,14 +2393,14 @@ export default class TicketsDataProvider {
2332
2393
  this.token,
2333
2394
  'get',
2334
2395
  {},
2335
- { Accept: accept }
2396
+ { Accept: accept },
2336
2397
  );
2337
2398
  if (iconDataUrl) break;
2338
2399
  } catch (error: any) {
2339
2400
  logger.warn(
2340
2401
  `Failed to download icon (${accept}) for work item type ${
2341
2402
  workItemType?.name ?? 'unknown'
2342
- }: ${error?.message || error}`
2403
+ }: ${error?.message || error}`,
2343
2404
  );
2344
2405
  }
2345
2406
  }
@@ -2348,8 +2409,8 @@ export default class TicketsDataProvider {
2348
2409
  const iconPayload = workItemType.icon
2349
2410
  ? { ...workItemType.icon, dataUrl: iconDataUrl }
2350
2411
  : iconDataUrl
2351
- ? { id: undefined, url: undefined, dataUrl: iconDataUrl }
2352
- : workItemType.icon;
2412
+ ? { id: undefined, url: undefined, dataUrl: iconDataUrl }
2413
+ : workItemType.icon;
2353
2414
 
2354
2415
  return {
2355
2416
  name: workItemType.name,
@@ -2358,7 +2419,7 @@ export default class TicketsDataProvider {
2358
2419
  icon: iconPayload,
2359
2420
  states: workItemType.states,
2360
2421
  };
2361
- })
2422
+ }),
2362
2423
  );
2363
2424
 
2364
2425
  return workItemTypesWithIcons;
@@ -2530,7 +2591,7 @@ export default class TicketsDataProvider {
2530
2591
  });
2531
2592
 
2532
2593
  logger.debug(
2533
- `Categorized ${workItemIds.length} work items into ${Object.keys(finalCategories).length} categories`
2594
+ `Categorized ${workItemIds.length} work items into ${Object.keys(finalCategories).length} categories`,
2534
2595
  );
2535
2596
 
2536
2597
  return {