1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
//! The only file-target policy.
//!
//! Every code path in drep that decides which files to look at goes through
//! these predicates, so a Python file is a file is a file regardless of whether
//! it was discovered by a full scan, the staged-files index, or a
//! `--diff <ref>` query. Markdown has its own predicate and its own command:
//! see `is_scan_target` for why the two file classes are disjoint.
//!
//! Walking is the `ignore` crate rather than `std::fs::read_dir` so a project's
//! gitignore is honoured without a second pass, and vendored directories are
//! pruned during the walk (rather than collected-then-filtered, which would
//! `stat` every entry under `node_modules/` before discarding them).
//!
//! Discovery of explicit filenames (`drep check a.rs .`) deliberately ignores
//! gitignore: the user naming a path is a stronger signal than a repo-wide
//! pattern. `expand_paths` enforces that; `walk_targets` enforces the inverse.
use ;
use ;
use ;
use cratelanguages;
/// Any registered language's source file - the file class `drep check` reads.
///
/// Markdown is **not** here, and that is the point. Each command owns one file
/// class: `check` reads code through this predicate, while `lint-docs` reads
/// markdown through [`is_markdown`]. A path the user names that falls outside
/// the running command's class is a
/// [`crate::analysis::result::FailureReason::Unsupported`] pointing at the
/// other command - never a silent skip.
/// Markdown document.
/// Hardcoded ignored dirs that belong to no single language: VCS metadata,
/// build output, caches.
const SHARED_IGNORED_DIRS: & = &;
/// A directory that should never be descended into.
///
/// Case-insensitive on purpose: a directory called `VENV` and one called `venv`
/// are the same on a case-insensitive filesystem, and matching only one of
/// them would walk it anyway — defeating the whole point of having the list.
/// Walk `root` and collect every regular file matching `predicate`.
///
/// Pruning happens **during** the walk via `ignore`'s `filter_entry`, so
/// ignoring `node_modules/` does not mean stat-ing every entry under it first
/// — the failure mode that `rglob` falls into on a real repo. Honors
/// per-directory `.gitignore`, which is the difference between a walk that
/// respects a project's policy and one that simply skips a directory named
/// `build`.
/// Expand a list of explicit paths (files and/or directories) into a sorted,
/// deduplicated set of files matching `predicate`.
///
/// Dedup because `drep check a.rs .` would otherwise pay a whole LLM
/// round-trip twice. An explicit file is filtered by the same predicate as
/// directory walks, so naming `notes.txt` cannot smuggle in a type drep does
/// not read; conversely, gitignore is *not* consulted for explicit files —
/// the user naming a path is a stronger signal than the repo's ignore file.
/// Paths that do not exist are skipped silently.
/// Why an explicitly named path produced no target.
///
/// Only *named* paths are ever rejected. A directory walk that yields nothing
/// is legitimately empty: `drep check .` in a documentation repository has
/// correctly found no code. A path the user typed is the opposite case, and
/// reporting "No issues found." for it is the single failure this codebase is
/// built to prevent.
/// The result of resolving a command's path arguments.
/// Resolve a command's path arguments against `root`.
///
/// The single answer to "what did the user ask for, and what could I not do
/// with it". [`expand_paths`] reports only the targets, which meant every
/// caller re-walked the same argument list with its own `exists()` /
/// `is_file()` tests to reconstruct what the expander had already decided and
/// thrown away. Two commands did that, and the reconstruction was lossy in the
/// same way in both: a named fifo satisfies neither `is_file` nor `is_dir`, so
/// it was dropped by the expander, missed by the reconstruction, and reported
/// as a clean run.
///
/// No arguments means `root`, which is how bare `drep check` means "the whole
/// tree". `root` goes through the expander like any other directory - an
/// earlier version returned it unexpanded, so `read_to_string` was handed a
/// *directory* and the plainest invocation of the primary command exited 2
/// without analyzing anything.
/// The subcommand that does analyze `path`, if any.
///
/// One table, consulted from both directions. Each command previously
/// hardcoded a pointer at the other - `check` asked `is_markdown`, `lint-docs`
/// asked `languages::detect` - which is two definitions of one question and an
/// edit in every existing command each time a file class is added.
/// What to tell a user who named `path` at the wrong command.
///
/// `None` when no command claims the type, because drep genuinely has nothing
/// to say about a `.png` and inventing a suggestion would be worse than
/// admitting that.