1
+ import os
1
2
import re
2
3
import glob
3
4
from collections import defaultdict
@@ -58,6 +59,12 @@ def explain(project_type, src_dir, bom_dir, vdr_file, vdr_result, explanation_mo
58
59
else "Reachable Flows"
59
60
)
60
61
for sf in slices_files :
62
+ if len (slices_files ) > 1 :
63
+ fn = os .path .basename (sf )
64
+ section_label = f"# Explanations for { sf } "
65
+ if "-" in fn :
66
+ section_label = f"# Explanations for { fn .split ('-' )[0 ].upper ()} "
67
+ console .print (Markdown (section_label ))
61
68
if (reachables_data := json_load (sf , log = LOG )) and reachables_data .get (
62
69
"reachables"
63
70
):
@@ -211,7 +218,7 @@ def explain_reachables(
211
218
project_type ,
212
219
vdr_result ,
213
220
)
214
- if not source_sink_desc or not flow_tree :
221
+ if not source_sink_desc or not flow_tree or len ( flow_tree . children ) < 5 :
215
222
continue
216
223
# In non-reachables mode, we are not interested in reachable flows.
217
224
if (
@@ -358,7 +365,7 @@ def flow_to_source_sink(idx, flow, purls, project_type, vdr_result):
358
365
source_sink_desc = f"Invocation: { method_full_name } "
359
366
elif flow .get ("label" ) == "RETURN" and flow .get ("code" ):
360
367
source_sink_desc = flow .get ("code" ).split ("\n " )[0 ]
361
- elif project_type not in ("java" ) and flow .get ("label" ) == "IDENTIFIER" :
368
+ elif project_type not in ("java" , ) and flow .get ("label" ) == "IDENTIFIER" :
362
369
source_sink_desc = flow .get ("code" ).split ("\n " )[0 ]
363
370
if source_sink_desc .endswith ("(" ):
364
371
source_sink_desc = f":diamond_suit: { source_sink_desc } )"
@@ -421,19 +428,21 @@ def filter_tags(tags):
421
428
422
429
423
430
def is_filterable_code (project_type , code ):
424
- match project_type :
425
- case "js" | "ts" | "javascript" | "typescript" | "bom" :
426
- for c in (
427
- "console.log" ,
428
- "thoughtLog(" ,
429
- "_tmp_" ,
430
- "LOG.debug(" ,
431
- "options.get(" ,
432
- "RET" ,
433
- "this." ,
434
- ):
435
- if code and code .startswith (c ):
436
- return True
431
+ if len (code ) < 5 :
432
+ return True
433
+ for c in (
434
+ "console.log" ,
435
+ "thoughtLog(" ,
436
+ "_tmp_" ,
437
+ "LOG.debug(" ,
438
+ "options.get(" ,
439
+ "RET" ,
440
+ "this." ,
441
+ "NULL" ,
442
+ "!" ,
443
+ ):
444
+ if code and code .startswith (c ):
445
+ return True
437
446
return False
438
447
439
448
@@ -450,17 +459,21 @@ def flow_to_str(explanation_mode, flow, project_type):
450
459
node_desc = flow .get ("code" ).split ("\n " )[0 ]
451
460
if node_desc .endswith ("(" ):
452
461
node_desc = f":diamond_suit: { node_desc } )"
462
+ elif node_desc .startswith ("return " ):
463
+ node_desc = f":arrow_backward: [italic]{ node_desc } [/italic]"
453
464
tags = filter_tags (flow .get ("tags" ))
454
- if flow .get ("label" ) == "METHOD_PARAMETER_IN" :
465
+ if flow .get ("label" ) in ( "METHOD_PARAMETER_IN" ,) :
455
466
param_name = flow .get ("name" )
456
467
if param_name == "this" :
457
468
param_name = ""
458
469
node_desc = f"{ flow .get ('parentMethodName' )} ([red]{ param_name } [/red]) :right_arrow_curving_left:"
459
470
if tags :
460
471
node_desc = f"{ node_desc } \n [bold]Tags:[/bold] [italic]{ tags } [/italic]\n "
461
- elif flow .get ("label" ) == "IDENTIFIER" :
472
+ elif flow .get ("label" ) in ( "IDENTIFIER" , "CALL" ) :
462
473
if node_desc .startswith ("<" ):
463
474
node_desc = flow .get ("name" )
475
+ if flow .get ("isExternal" ):
476
+ node_desc = f"{ node_desc } :right_arrow_curving_up:"
464
477
if tags :
465
478
node_desc = f"{ node_desc } \n [bold]Tags:[/bold] [italic]{ tags } [/italic]\n "
466
479
if tags and not is_filterable_code (project_type , node_desc ):
@@ -528,7 +541,7 @@ def explain_flows(explanation_mode, flows, purls, project_type, vdr_result):
528
541
file_loc , flow_str , node_desc , has_check_tag_flow = flow_to_str (
529
542
explanation_mode , aflow , project_type
530
543
)
531
- if last_file_loc and last_file_loc == file_loc :
544
+ if not flow_str or ( last_file_loc and last_file_loc == file_loc ) :
532
545
continue
533
546
last_file_loc = file_loc
534
547
if flow_str in added_flows or node_desc in added_node_desc :
0 commit comments