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
//! What:
//! The `exclude` option of `markdown/autofix`:
//! gitignore-syntax patterns,
//! relative to
//! the repository's top level,
//! naming candidates the policy leaves alone.
//! Why:
//! The installed wrapper filtered candidates with the `ignore` package before starting
//! the linter (`rewrite-candidates.ts`,
//! `rewriteCandidates`),
//! so an excluded file never
//! starts a linter and never fails for one.
//! The linter evaluates its own copy of the
//! option with the `ignore` crate's gitignore matcher and a walk over ancestor
//! directories (`package/linter/monochromatic-lint/src/markdown_lfs_patterns.rs`);
//! this
//! module uses the same matcher and the same walk,
//! so both agree on every path.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! // const excluded = ignore().add(exclude); if (excluded.ignores(candidate.path)) continue;
//! ```
/// Import the conversion of Git's pathname bytes to a path.
use cratepath_from_git_bytes;
/// What:
/// `Gitignore` is a compiled pattern list;
/// `GitignoreBuilder` compiles one.
/// Why:
/// The same compiler the linter and the scanner use.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// import ignore from 'ignore';
/// ```
use ;
/// What:
/// The compiled patterns.
/// The field is private:
/// build one with `compile_exclude`.
/// Why:
/// Compiled once per invocation,
/// then asked once per Markdown candidate.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// type ExcludeMatcher = { ignores(path: string): boolean };
/// ```
/// What:
/// Compile `patterns` in order.
/// `Result<ExcludeMatcher, String>` is the matcher or
/// the reason a pattern was refused,
/// naming it.
/// Why:
/// A pattern that cannot compile must not silently match nothing.
/// The empty root
/// keeps candidate paths as Git prints them:
/// relative to the top level.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// function compileExclude(patterns: string[]): ExcludeMatcher;
/// ```
/// What:
/// `impl ExcludeMatcher { ... }` attaches the one question it answers.
/// Why:
/// Callers never see the walk over ancestor directories.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// class ExcludeMatcher { excludes(path: Uint8Array): boolean }
/// ```
/// What:
/// Whether one byte is `/`,
/// the separator of Git pathnames.
/// Why:
/// A named predicate for `split`,
/// because the repository bans anonymous functions.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const isSlash = (byte: number) => byte === 0x2f;
/// ```
/// Pattern and ancestor-walk controls stay out of the release executable.