Skip to content

Commit a303895

Browse files
cristianocclaude
andcommitted
Add glob pattern support for reanalyze suppress/unsuppress
Support `*` and `**` glob patterns in `reanalyze.suppress` and `reanalyze.unsuppress` config entries (e.g. `**/bindings`, `src/Dead*`). Plain prefix strings continue to work as before. Closes #8259 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3f889ed commit a303895

2 files changed

Lines changed: 70 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#### :rocket: New Feature
2020

21+
- Reanalyze: add glob pattern support for suppress/unsuppress configurations (e.g., `"src/generated/**"`). https://github.com/rescript-lang/rescript/pull/8277
22+
2123
#### :bug: Bug fix
2224

2325
- Reanalyze server: invalidate cache and recompute results when config changes in `rescript.json`. https://github.com/rescript-lang/rescript/pull/8262

analysis/reanalyze/src/Suppress.ml

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,85 @@
11
let runConfig = RunConfig.runConfig
22

3-
let checkPrefix prefix_ =
4-
let prefix =
3+
let normalize_separators s =
4+
if Sys.win32 then String.map (fun c -> if c = '\\' then '/' else c) s else s
5+
6+
let split_on_slash s =
7+
let rec aux acc start i =
8+
if i >= String.length s then
9+
let last = String.sub s start (i - start) in
10+
if last = "" then acc else last :: acc
11+
else if s.[i] = '/' then
12+
let seg = String.sub s start (i - start) in
13+
let acc = if seg = "" then acc else seg :: acc in
14+
aux acc (i + 1) (i + 1)
15+
else aux acc start (i + 1)
16+
in
17+
List.rev (aux [] 0 0)
18+
19+
let has_glob_char s = String.contains s '*'
20+
21+
(** Match glob pattern segments against path segments.
22+
A single star matches one path segment, a double star matches zero or more.
23+
Matches as a prefix: if the pattern is exhausted, the remaining path is accepted. *)
24+
let rec glob_match pattern_segs path_segs =
25+
match (pattern_segs, path_segs) with
26+
| [], _ -> true
27+
| "**" :: rest, _ -> (
28+
glob_match rest path_segs
29+
||
30+
match path_segs with
31+
| _ :: path_rest -> glob_match pattern_segs path_rest
32+
| [] -> false)
33+
| _ :: _, [] -> false
34+
| pat :: pat_rest, seg :: path_rest ->
35+
glob_segment pat seg && glob_match pat_rest path_rest
36+
37+
and glob_segment pattern segment =
38+
let rec aux pi si =
39+
if pi >= String.length pattern then si >= String.length segment
40+
else if pattern.[pi] = '*' then
41+
let rec try_skip si' =
42+
si' <= String.length segment && (aux (pi + 1) si' || try_skip (si' + 1))
43+
in
44+
try_skip si
45+
else
46+
si < String.length segment
47+
&& pattern.[pi] = segment.[si]
48+
&& aux (pi + 1) (si + 1)
49+
in
50+
aux 0 0
51+
52+
let checkPattern pattern_ =
53+
let is_glob = has_glob_char pattern_ in
54+
let pattern =
555
match runConfig.projectRoot = "" with
6-
| true -> prefix_
7-
| false -> Filename.concat runConfig.projectRoot prefix_
56+
| true -> pattern_
57+
| false -> Filename.concat runConfig.projectRoot pattern_
858
in
9-
let prefixLen = prefix |> String.length in
10-
fun sourceDir ->
11-
try String.sub sourceDir 0 prefixLen = prefix
12-
with Invalid_argument _ -> false
59+
let pattern = normalize_separators pattern in
60+
if is_glob then
61+
let pattern_segs = split_on_slash pattern in
62+
fun sourceDir ->
63+
let path_segs = split_on_slash (normalize_separators sourceDir) in
64+
glob_match pattern_segs path_segs
65+
else
66+
let prefixLen = pattern |> String.length in
67+
fun sourceDir ->
68+
let sourceDir = normalize_separators sourceDir in
69+
try String.sub sourceDir 0 prefixLen = pattern
70+
with Invalid_argument _ -> false
1371

1472
let suppressSourceDir =
1573
lazy
1674
(fun sourceDir ->
1775
runConfig.suppress
18-
|> List.exists (fun prefix -> checkPrefix prefix sourceDir))
76+
|> List.exists (fun pattern -> checkPattern pattern sourceDir))
1977

2078
let unsuppressSourceDir =
2179
lazy
2280
(fun sourceDir ->
2381
runConfig.unsuppress
24-
|> List.exists (fun prefix -> checkPrefix prefix sourceDir))
82+
|> List.exists (fun pattern -> checkPattern pattern sourceDir))
2583

2684
let posInSuppress (pos : Lexing.position) =
2785
pos.pos_fname |> Lazy.force suppressSourceDir

0 commit comments

Comments
 (0)