phpstan-mcp-mx 0.22.0 → 0.24.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +142 -19
  3. package/dist/baseline.d.ts +10 -0
  4. package/dist/baseline.js +36 -14
  5. package/dist/baseline.js.map +1 -1
  6. package/dist/changed.d.ts +17 -0
  7. package/dist/changed.js +56 -29
  8. package/dist/changed.js.map +1 -1
  9. package/dist/compare.js +12 -6
  10. package/dist/compare.js.map +1 -1
  11. package/dist/composer.js +43 -21
  12. package/dist/composer.js.map +1 -1
  13. package/dist/config.js +12 -6
  14. package/dist/config.js.map +1 -1
  15. package/dist/defaults.js +2 -1
  16. package/dist/defaults.js.map +1 -1
  17. package/dist/dumptype.js +16 -8
  18. package/dist/dumptype.js.map +1 -1
  19. package/dist/failure.d.ts +1 -1
  20. package/dist/failure.js.map +1 -1
  21. package/dist/history.d.ts +61 -0
  22. package/dist/history.js +275 -0
  23. package/dist/history.js.map +1 -0
  24. package/dist/index.js +6 -3
  25. package/dist/index.js.map +1 -1
  26. package/dist/php.js +10 -5
  27. package/dist/php.js.map +1 -1
  28. package/dist/phpstan/error.js.map +1 -1
  29. package/dist/phpstan/output.js +12 -6
  30. package/dist/phpstan/output.js.map +1 -1
  31. package/dist/phpstan/parameters.js.map +1 -1
  32. package/dist/phpstan/process.d.ts +10 -0
  33. package/dist/phpstan/process.js +35 -9
  34. package/dist/phpstan/process.js.map +1 -1
  35. package/dist/phpstan/queue.js +4 -2
  36. package/dist/phpstan/queue.js.map +1 -1
  37. package/dist/phpstan.d.ts +14 -0
  38. package/dist/phpstan.js +94 -25
  39. package/dist/phpstan.js.map +1 -1
  40. package/dist/project.d.ts +6 -2
  41. package/dist/project.js +57 -18
  42. package/dist/project.js.map +1 -1
  43. package/dist/prune.d.ts +92 -0
  44. package/dist/prune.js +387 -0
  45. package/dist/prune.js.map +1 -0
  46. package/dist/report.js +38 -19
  47. package/dist/report.js.map +1 -1
  48. package/dist/root-source.d.ts +43 -0
  49. package/dist/root-source.js +124 -0
  50. package/dist/root-source.js.map +1 -0
  51. package/dist/roots.d.ts +12 -0
  52. package/dist/roots.js +23 -6
  53. package/dist/roots.js.map +1 -1
  54. package/dist/runner.js +14 -7
  55. package/dist/runner.js.map +1 -1
  56. package/dist/runs.js +6 -3
  57. package/dist/runs.js.map +1 -1
  58. package/dist/schema-dialect.js +6 -3
  59. package/dist/schema-dialect.js.map +1 -1
  60. package/dist/server.d.ts +3 -2
  61. package/dist/server.js +9 -5
  62. package/dist/server.js.map +1 -1
  63. package/dist/tmpdir.js +6 -3
  64. package/dist/tmpdir.js.map +1 -1
  65. package/dist/tools/analysis.d.ts +4 -4
  66. package/dist/tools/analysis.js +4 -2
  67. package/dist/tools/analysis.js.map +1 -1
  68. package/dist/tools/inspect.d.ts +9 -7
  69. package/dist/tools/inspect.js +158 -37
  70. package/dist/tools/inspect.js.map +1 -1
  71. package/dist/tools/prompts.d.ts +3 -3
  72. package/dist/tools/prompts.js +16 -8
  73. package/dist/tools/prompts.js.map +1 -1
  74. package/dist/tools/shared.d.ts +2 -2
  75. package/dist/tools/shared.js +7 -5
  76. package/dist/tools/shared.js.map +1 -1
  77. package/dist/tools/writes.d.ts +8 -3
  78. package/dist/tools/writes.js +73 -3
  79. package/dist/tools/writes.js.map +1 -1
  80. package/dist/tools.d.ts +2 -2
  81. package/dist/tools.js +6 -3
  82. package/dist/tools.js.map +1 -1
  83. package/dist/unmatched.d.ts +66 -0
  84. package/dist/unmatched.js +194 -44
  85. package/dist/unmatched.js.map +1 -1
  86. package/dist/version.js.map +1 -1
  87. package/package.json +1 -1
package/dist/prune.js ADDED
@@ -0,0 +1,387 @@
1
+ import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join, normalize, resolve } from 'node:path';
3
+ import { BaselineError, includedBaselineFiles, unquote } from './baseline.js';
4
+ import { PhpstanError } from './phpstan.js';
5
+ import { analyseUnmatched, readStaleInline, readStaleRule, unmatchedGeneralPattern } from './unmatched.js';
6
+ /** Tekens die van een pad een fnmatch-patroon maken; zo'n pad bestaat nooit letterlijk. */
7
+ const GLOB = /[*?[\]]/;
8
+ /**
9
+ * Snoeit de baselines die de config includeert: entries die niets meer matchen gaan eruit,
10
+ * een te hoge `count` gaat omlaag naar wat nog voorkomt. Er komt nooit iets bij.
11
+ *
12
+ * Dat is het verschil met `generate_baseline`: die ruimt ook op, maar zet alles wat nu
13
+ * gemeld wordt erbij, en dan verdwijnt het uit elke volgende analyse. Opruimen en verstoppen
14
+ * horen twee handelingen te zijn.
15
+ *
16
+ * Geen verse baseline naast de oude leggen: zolang de oude geïncludeerd is, negeert PHPStan
17
+ * die fouten al, en een verse baseline zou dan bijna leeg zijn. PHPStans eigen
18
+ * `reportUnmatchedIgnoredErrors` zegt per entry wat er niet meer klopt; dat is dezelfde run
19
+ * als `unmatched_ignores`.
20
+ *
21
+ * Alles wat niet eenduidig terug te vinden is, blijft staan. Een fout in het koppelen laat
22
+ * dus hooguit een verouderde entry achter, en haalt nooit een entry weg die nog iets doet.
23
+ */
24
+ export async function pruneBaseline(project, options = {}, analyse = analyseUnmatched) {
25
+ const files = includedBaselineFiles(project);
26
+ // Zonder config includeert includedBaselineFiles niets; dit dekt dus ook dat geval.
27
+ if (project.config === null || files.length === 0) {
28
+ return nothingIncluded(project, noBaselineReason(project));
29
+ }
30
+ const before = new Map(files.map((file) => [file, readParsed(project, file)]));
31
+ // Eerst de entries voor een bestand dat er niet meer is. Met reportUnmatchedIgnoredErrors
32
+ // aan weigert PHPStan de héle run op zo'n pad ("is neither a directory, nor a file path"),
33
+ // dus dit moet vóór de analyse op schijf staan. Een bestand dat er niet is, kan geen fout
34
+ // hebben: weghalen verbergt niets.
35
+ const missing = new Map();
36
+ for (const file of files) {
37
+ const parsed = before.get(file);
38
+ const dead = parsed.blocks.filter((block) => block.known && block.path !== null && !GLOB.test(block.path) && !existsSync(resolve(project.path, dirname(file), block.path)));
39
+ if (dead.length > 0) {
40
+ writeBaseline(project, file, applyEdits(parsed, new Set(dead), new Map()));
41
+ missing.set(file, dead.length);
42
+ }
43
+ }
44
+ let result;
45
+ try {
46
+ result = await analyse(project, project.config, options);
47
+ }
48
+ catch (error) {
49
+ throw withMissingNotice(error, missing);
50
+ }
51
+ requireComplete(result, missing);
52
+ const rules = [];
53
+ let currentFindings = 0;
54
+ let inline = 0;
55
+ for (const finding of result.findings) {
56
+ // Een inline ignore die niets meer doet, staat in de code: dat is niet aan deze tool, en
57
+ // ook geen huidige bevinding die de baseline zou kunnen verstoppen.
58
+ if (readStaleInline(finding) !== null) {
59
+ inline++;
60
+ continue;
61
+ }
62
+ const rule = readStaleRule(finding, project.path);
63
+ // Een count die te laag is, is geen verouderde regel: de fout komt vaker voor, en die
64
+ // extra keer is een bevinding. Verhogen zou hem verstoppen.
65
+ if (rule === null || rule.kind === 'countTooLow') {
66
+ currentFindings++;
67
+ }
68
+ else {
69
+ rules.push(rule);
70
+ }
71
+ }
72
+ const general = result.generalErrors.filter((error) => unmatchedGeneralPattern(error) !== null).length;
73
+ const perFile = [];
74
+ const claimed = new Set();
75
+ let unknownCount = 0;
76
+ // Opnieuw inlezen: het bestand kan hierboven al gesnoeid zijn, en de regelnummers van
77
+ // toen kloppen dan niet meer.
78
+ const current = new Map(files.map((file) => [file, readParsed(project, file)]));
79
+ const edits = new Map(files.map((file) => [file, { remove: new Set(), lower: new Map() }]));
80
+ for (const rule of rules) {
81
+ const found = findBlock(project, current, rule, claimed);
82
+ if (found === null) {
83
+ continue;
84
+ }
85
+ claimed.add(found.block);
86
+ const edit = edits.get(found.file);
87
+ // Alleen omlaag, en alleen naar een getal dat PHPStan zelf noemde.
88
+ if (rule.kind === 'unmatched') {
89
+ edit.remove.add(found.block);
90
+ }
91
+ else if (rule.occurred === null || found.block.countLine === null || rule.occurred >= found.block.count) {
92
+ unknownCount++;
93
+ }
94
+ else {
95
+ edit.lower.set(found.block, rule.occurred);
96
+ }
97
+ }
98
+ for (const file of files) {
99
+ const parsed = current.get(file);
100
+ const edit = edits.get(file);
101
+ if (edit.remove.size > 0 || edit.lower.size > 0) {
102
+ writeBaseline(project, file, applyEdits(parsed, edit.remove, edit.lower));
103
+ }
104
+ const original = before.get(file);
105
+ const errorsAfter = errorsIn(parsed) - sumCounts(edit.remove) - [...edit.lower].reduce((sum, [block, count]) => sum + block.count - count, 0);
106
+ perFile.push({
107
+ file,
108
+ removed: edit.remove.size + (missing.get(file) ?? 0),
109
+ lowered: edit.lower.size,
110
+ errorsBefore: errorsIn(original),
111
+ errorsAfter,
112
+ });
113
+ }
114
+ return {
115
+ project: project.path,
116
+ files: perFile,
117
+ totals: {
118
+ removed: perFile.reduce((sum, file) => sum + file.removed, 0),
119
+ lowered: perFile.reduce((sum, file) => sum + file.lowered, 0),
120
+ missingFiles: [...missing.values()].reduce((sum, count) => sum + count, 0),
121
+ errorsBefore: perFile.reduce((sum, file) => sum + file.errorsBefore, 0),
122
+ errorsAfter: perFile.reduce((sum, file) => sum + file.errorsAfter, 0),
123
+ },
124
+ left: { outsideBaseline: rules.length - claimed.size, general, unknownCount, inline },
125
+ currentFindings,
126
+ notices: [],
127
+ };
128
+ }
129
+ /**
130
+ * Leest een baseline in blokken, met regelnummers, zodat een wijziging alleen die blokken
131
+ * raakt en de rest van het bestand byte voor byte blijft staan. Regelgericht, net als
132
+ * `parseBaseline`: PHPStan genereert dit bestand, dus de vorm ligt vast.
133
+ */
134
+ export function parseBaselineBlocks(content) {
135
+ const eol = content.includes('\r\n') ? '\r\n' : '\n';
136
+ const lines = content.split(/\r?\n/);
137
+ const listLine = lines.findIndex((line) => /^\s*ignoreErrors:\s*$/.test(line));
138
+ if (listLine === -1) {
139
+ return { lines, eol, listLine: null, blocks: [] };
140
+ }
141
+ const listIndent = indentOf(lines[listLine] ?? '');
142
+ const blocks = [];
143
+ let itemIndent = null;
144
+ let open = null;
145
+ let index = listLine + 1;
146
+ const close = (end) => {
147
+ if (open !== null) {
148
+ blocks.push(toBlock(open.start, end, open.known, open.fields));
149
+ }
150
+ open = null;
151
+ };
152
+ for (; index < lines.length; index++) {
153
+ const line = lines[index] ?? '';
154
+ const trimmed = line.trim();
155
+ if (trimmed === '') {
156
+ continue;
157
+ }
158
+ const indent = indentOf(line);
159
+ if (indent <= listIndent) {
160
+ break;
161
+ }
162
+ // Een nieuw lijstitem op dezelfde diepte als het eerste. `- message: …` op één regel
163
+ // maakt PHPStan niet; zo'n blok is een grens, maar wordt niet gelezen of aangeraakt.
164
+ if (trimmed.startsWith('-') && (itemIndent === null || indent === itemIndent)) {
165
+ itemIndent ??= indent;
166
+ close(index);
167
+ open = { start: index, known: trimmed === '-', fields: new Map() };
168
+ continue;
169
+ }
170
+ const field = /^(identifier|path|count|message|rawMessage):\s*(.*)$/.exec(trimmed);
171
+ if (open !== null && field?.[1] !== undefined) {
172
+ open.fields.set(field[1], { value: (field[2] ?? '').trim(), line: index });
173
+ }
174
+ }
175
+ close(index);
176
+ return { lines, eol, listLine, blocks };
177
+ }
178
+ /**
179
+ * Past de wijzigingen toe en geeft de nieuwe inhoud. Weghalen gaat per blok inclusief de
180
+ * lege regels erna; een lagere count vervangt alleen het getal op zijn eigen regel.
181
+ */
182
+ export function applyEdits(parsed, remove, lower) {
183
+ const lines = [...parsed.lines];
184
+ for (const [block, count] of lower) {
185
+ if (block.countLine !== null) {
186
+ lines[block.countLine] = (lines[block.countLine] ?? '').replace(/count:\s*\d+/, `count: ${String(count)}`);
187
+ }
188
+ }
189
+ const dropped = new Set();
190
+ for (const block of remove) {
191
+ for (let line = block.start; line < block.end; line++) {
192
+ dropped.add(line);
193
+ }
194
+ }
195
+ // De laatste regel is leeg als het bestand op een regeleinde eindigt; die hoort bij het
196
+ // bestand en niet bij het laatste blok.
197
+ const last = lines.length - 1;
198
+ if (lines[last] === '') {
199
+ dropped.delete(last);
200
+ }
201
+ const kept = lines.filter((_, index) => !dropped.has(index));
202
+ // Alles weg: `ignoreErrors:` zonder lijst eronder is in NEON null, en daar valt PHPStan
203
+ // over. Een lege lijst is wat er dan bedoeld wordt.
204
+ if (parsed.listLine !== null && remove.size === parsed.blocks.length) {
205
+ const at = kept.indexOf(parsed.lines[parsed.listLine] ?? '');
206
+ if (at !== -1) {
207
+ kept[at] = (kept[at] ?? '').replace(/ignoreErrors:\s*$/, 'ignoreErrors: []');
208
+ }
209
+ }
210
+ return kept.join(parsed.eol);
211
+ }
212
+ /** Schrijft een overzicht van wat er gedaan is, als tekst voor het model. */
213
+ export function renderPruned(result) {
214
+ const lines = [];
215
+ if (result.notices.length > 0) {
216
+ lines.push(...result.notices.map((notice) => `Note: ${notice}`), '');
217
+ }
218
+ const changed = result.files.filter((file) => file.removed > 0 || file.lowered > 0);
219
+ if (changed.length === 0) {
220
+ lines.push(result.files.length === 0
221
+ ? 'Nothing to prune.'
222
+ : `Nothing to prune: every entry in ${result.files.map((file) => file.file).join(', ')} still matches.`);
223
+ }
224
+ for (const file of changed) {
225
+ const delen = [`removed ${file.removed} ${file.removed === 1 ? 'entry' : 'entries'}`];
226
+ if (file.lowered > 0) {
227
+ delen.push(`lowered the count of ${file.lowered}`);
228
+ }
229
+ lines.push(`${file.file}: ${delen.join(', ')}; ${file.errorsBefore} → ${file.errorsAfter} ignored error(s).`);
230
+ }
231
+ if (result.totals.missingFiles > 0) {
232
+ lines.push(`${result.totals.missingFiles} of the removed entries named a file that no longer exists.`);
233
+ }
234
+ lines.push('', result.currentFindings > 0
235
+ ? `Nothing was added: the ${result.currentFindings} current finding(s) are still reported. Fix them at the ` +
236
+ 'source; generate_baseline would hide them in the baseline.'
237
+ : 'Nothing was added, and there are no current findings.');
238
+ const { left } = result;
239
+ if (left.outsideBaseline + left.general + left.unknownCount + left.inline > 0) {
240
+ lines.push('', 'Left alone:');
241
+ if (left.outsideBaseline > 0) {
242
+ lines.push(`- ${left.outsideBaseline} stale rule(s) with a path that are not in an included baseline: they are in ignoreErrors of the config. Edit that yourself.`);
243
+ }
244
+ if (left.general > 0) {
245
+ lines.push(`- ${left.general} pattern(s) without a path: from ignoreErrors of a config, often one a package ships. A baseline change does nothing about them.`);
246
+ }
247
+ if (left.unknownCount > 0) {
248
+ lines.push(`- ${left.unknownCount} count(s) that are too high, where PHPStan did not say how often the error still occurs.`);
249
+ }
250
+ if (left.inline > 0) {
251
+ lines.push(`- ${left.inline} inline @phpstan-ignore comment(s) that no longer suppress anything: those are in the code. unmatched_ignores lists them.`);
252
+ }
253
+ }
254
+ return lines.join('\n');
255
+ }
256
+ function toBlock(start, end, known, fields) {
257
+ const value = (key) => {
258
+ const field = fields.get(key);
259
+ return field === undefined ? null : unquote(field.value);
260
+ };
261
+ const message = value('message');
262
+ const raw = value('rawMessage');
263
+ const count = fields.get('count');
264
+ return {
265
+ start,
266
+ end,
267
+ known,
268
+ path: value('path'),
269
+ identifier: value('identifier'),
270
+ // Zoals PHPStans IgnoredError::stringifyPattern het schrijft: `rawMessage` tussen dubbele
271
+ // quotes, zodat hij te koppelen is aan de melding over een verouderde regel.
272
+ pattern: message ?? (raw === null ? null : `"${raw}"`),
273
+ count: count === undefined ? 1 : Number.parseInt(count.value, 10) || 1,
274
+ countLine: count?.line ?? null,
275
+ };
276
+ }
277
+ /**
278
+ * Het blok dat bij een verouderde regel hoort, of null als het niet eenduidig te vinden is.
279
+ * Een blok wordt maar één keer gebruikt: twee gelijke entries leveren twee meldingen op.
280
+ */
281
+ function findBlock(project, baselines, rule, claimed) {
282
+ for (const [file, parsed] of baselines) {
283
+ for (const block of parsed.blocks) {
284
+ if (!claimed.has(block) && matches(project, file, block, rule)) {
285
+ return { file, block };
286
+ }
287
+ }
288
+ }
289
+ return null;
290
+ }
291
+ function matches(project, file, block, rule) {
292
+ if (!block.known || block.path === null || !samePath(resolve(project.path, dirname(file), block.path), rule.file)) {
293
+ return false;
294
+ }
295
+ // Een regel met alleen een identifier noemt PHPStan bij die identifier, zonder haakjes.
296
+ if (block.pattern === null) {
297
+ return rule.identifier === null && rule.pattern === block.identifier;
298
+ }
299
+ return rule.pattern === block.pattern && rule.identifier === block.identifier;
300
+ }
301
+ function samePath(a, b) {
302
+ // Windows vergelijkt zonder hoofdletters, en PHPStan schrijft het pad zoals het die kreeg.
303
+ return process.platform === 'win32' ? normalize(a).toLowerCase() === normalize(b).toLowerCase() : normalize(a) === normalize(b);
304
+ }
305
+ /**
306
+ * Een onvolledige analyse laat entries verouderd lijken die dat niet zijn. Dan wordt er
307
+ * niets geschreven: liever niets snoeien dan een baseline half leeghalen omdat PHPStan
308
+ * halverwege klapte.
309
+ */
310
+ function requireComplete(result, missing) {
311
+ const incomplete = result.warnings.find((warning) => /Result is incomplete/i.test(warning));
312
+ const errors = result.generalErrors.filter((error) => unmatchedGeneralPattern(error) === null);
313
+ if (incomplete === undefined && errors.length === 0) {
314
+ return;
315
+ }
316
+ const reason = incomplete ?? errors.slice(0, 3).join('\n');
317
+ throw withMissingNotice(new PhpstanError(`The analysis did not cover the whole project, so the baseline was not pruned: an entry can look stale ` +
318
+ `when PHPStan simply did not get that far.\n\n${reason}`, 'phpstan_failed'), missing);
319
+ }
320
+ /** Een fout na het weghalen van entries voor verdwenen bestanden: dat is dan wél gebeurd. */
321
+ function withMissingNotice(error, missing) {
322
+ if (missing.size === 0 || !(error instanceof PhpstanError)) {
323
+ return error;
324
+ }
325
+ const wat = [...missing].map(([file, count]) => `${count} from ${file}`).join(', ');
326
+ return new PhpstanError(`${error.message}\n\nAlready removed before the analysis: the entries for files that no longer exist (${wat}).`, error.reason, error.details);
327
+ }
328
+ function readParsed(project, file) {
329
+ let content;
330
+ try {
331
+ content = readFileSync(join(project.path, file), 'utf8');
332
+ }
333
+ catch (error) {
334
+ throw new BaselineError(`${file} cannot be read: ${error instanceof Error ? error.message : String(error)}.`);
335
+ }
336
+ const parsed = parseBaselineBlocks(content);
337
+ // Hetzelfde onderscheid als bij baseline_summary: ignoreErrors noemen en niets opleveren is
338
+ // een vorm die we niet kennen, en daar wordt niet in geschreven.
339
+ if (parsed.blocks.filter((block) => block.known).length === 0 && parsed.blocks.length > 0) {
340
+ throw new BaselineError(`${file} contains ignoreErrors, but not a single entry could be read from it; it was not changed.`);
341
+ }
342
+ return parsed;
343
+ }
344
+ /**
345
+ * Via een tijdelijk bestand naast het origineel en een rename: een analyse die tegelijk
346
+ * leest, ziet het oude of het nieuwe bestand en nooit een half.
347
+ */
348
+ function writeBaseline(project, file, content) {
349
+ const target = join(project.path, file);
350
+ const tmp = `${target}.phpstan-mcp-${String(process.pid)}`;
351
+ try {
352
+ writeFileSync(tmp, content);
353
+ renameSync(tmp, target);
354
+ }
355
+ catch (error) {
356
+ throw new BaselineError(`${file} could not be written: ${error instanceof Error ? error.message : String(error)}.`);
357
+ }
358
+ }
359
+ function nothingIncluded(project, notice) {
360
+ return {
361
+ project: project.path,
362
+ files: [],
363
+ totals: { removed: 0, lowered: 0, missingFiles: 0, errorsBefore: 0, errorsAfter: 0 },
364
+ left: { outsideBaseline: 0, general: 0, unknownCount: 0, inline: 0 },
365
+ currentFindings: 0,
366
+ notices: [notice],
367
+ };
368
+ }
369
+ function noBaselineReason(project) {
370
+ return project.config === null
371
+ ? `${project.path} has no phpstan.neon(.dist), so no baseline is included.`
372
+ : `The config of ${project.path} includes no phpstan-baseline*.neon from the project root; there is nothing to prune.`;
373
+ }
374
+ function errorsIn(parsed) {
375
+ return parsed.blocks.reduce((sum, block) => sum + block.count, 0);
376
+ }
377
+ function sumCounts(blocks) {
378
+ let sum = 0;
379
+ for (const block of blocks) {
380
+ sum += block.count;
381
+ }
382
+ return sum;
383
+ }
384
+ function indentOf(line) {
385
+ return /^\s*/.exec(line)?.[0].length ?? 0;
386
+ }
387
+ //# sourceMappingURL=prune.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prune.js","sourceRoot":"","sources":["../src/prune.ts"],"names":[],"mappings":"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"}
package/dist/report.js CHANGED
@@ -79,8 +79,9 @@ export function buildReport(result, window = {}, notices = [], onChangedLine, co
79
79
  }
80
80
  /** Lege of alleen-witruimte-waarden vallen weg; blijft er niets over, dan is er geen filter. */
81
81
  function normaliseFilter(identifiers) {
82
- if (identifiers === undefined)
82
+ if (identifiers === undefined) {
83
83
  return null;
84
+ }
84
85
  const cleaned = [...new Set(identifiers.map((value) => value.trim()).filter((value) => value !== ''))];
85
86
  return cleaned.length === 0 ? null : cleaned;
86
87
  }
@@ -91,8 +92,9 @@ function normaliseFilter(identifiers) {
91
92
  * zijn. Blijft er niets over, dan is er geen filter, net als bij identifiers.
92
93
  */
93
94
  function normalisePlaces(project, places) {
94
- if (places === undefined)
95
+ if (places === undefined) {
95
96
  return null;
97
+ }
96
98
  const cleaned = [
97
99
  ...new Set(places
98
100
  .map((place) => place.trim())
@@ -117,8 +119,9 @@ function isIn(file, places) {
117
119
  * containment-check op paden.
118
120
  */
119
121
  function matches(finding, filter) {
120
- if (finding.identifier === null)
122
+ if (finding.identifier === null) {
121
123
  return false;
124
+ }
122
125
  const identifier = finding.identifier;
123
126
  return filter.some((value) => identifier === value || identifier.startsWith(`${value}.`));
124
127
  }
@@ -131,22 +134,26 @@ export function renderReport(report, runId) {
131
134
  // Bovenaan, vóór de fouten: dit bepaalt of je de uitslag hieronder mag vertrouwen.
132
135
  if (report.warnings.length > 0) {
133
136
  lines.push('WARNING PHPStan reported this alongside the result:');
134
- for (const warning of report.warnings)
137
+ for (const warning of report.warnings) {
135
138
  lines.push(`- ${warning}`);
136
- if (report.omitted.warnings > 0)
139
+ }
140
+ if (report.omitted.warnings > 0) {
137
141
  lines.push(`- (${report.omitted.warnings} more message(s) not shown)`);
142
+ }
138
143
  lines.push('');
139
144
  }
140
145
  if (report.notices.length > 0) {
141
146
  lines.push('Note:');
142
- for (const notice of report.notices)
147
+ for (const notice of report.notices) {
143
148
  lines.push(`- ${notice}`);
149
+ }
144
150
  lines.push('');
145
151
  }
146
152
  if (report.generalErrors.length > 0) {
147
153
  lines.push('Errors not tied to a file:');
148
- for (const error of report.generalErrors)
154
+ for (const error of report.generalErrors) {
149
155
  lines.push(`- ${error}`);
156
+ }
150
157
  if (report.omitted.generalErrors > 0) {
151
158
  lines.push(`- (${report.omitted.generalErrors} more error(s) not shown)`);
152
159
  }
@@ -154,16 +161,18 @@ export function renderReport(report, runId) {
154
161
  }
155
162
  // Vóór de vroege uitgang bij nul bevindingen: "alles opgelost" is juist het geval
156
163
  // waarin de vergelijking het meest zegt.
157
- if (report.comparison !== null)
164
+ if (report.comparison !== null) {
158
165
  lines.push(...describeComparison(report.comparison), '');
166
+ }
159
167
  const filters = describeFilters(report);
160
168
  const changes = report.changedLines === null ? null : describeChangedLines(report.changedLines, report.comparison?.basis === 'base');
161
169
  if (report.page.total === 0) {
162
170
  if (filters !== null && report.totals.fileErrors > 0) {
163
171
  lines.push(`No findings ${filters}, ` +
164
172
  `but there are ${report.totals.fileErrors} other finding(s).`);
165
- if (changes !== null)
173
+ if (changes !== null) {
166
174
  lines.push(changes);
175
+ }
167
176
  return lines.join('\n');
168
177
  }
169
178
  const zonderContext = report.generalErrors.length === 0 && report.warnings.length === 0 && report.notices.length === 0;
@@ -173,8 +182,9 @@ export function renderReport(report, runId) {
173
182
  lines.push(filters === null
174
183
  ? `${report.page.total} finding(s) in ${report.summary.filesWithFindings} file(s).`
175
184
  : `${report.page.total} finding(s) ${filters}, of ${report.totals.fileErrors} in total.`);
176
- if (changes !== null)
185
+ if (changes !== null) {
177
186
  lines.push(changes);
187
+ }
178
188
  lines.push('', filters === null
179
189
  ? 'Most common:'
180
190
  : 'Most common (across all findings, including filtered ones):', ...report.summary.byIdentifier.map((row) => ` ${pad(row.count)} ${row.identifier}`),
@@ -204,13 +214,15 @@ export function renderReport(report, runId) {
204
214
  const mark = marked ? (finding.onChangedLine === true ? '+ ' : ' ') : '';
205
215
  const where = finding.line === null ? ' ?' : String(finding.line).padStart(4);
206
216
  lines.push(`${mark}${where} ${finding.identifier ?? '-'} ${finding.message}`);
207
- if (finding.tip !== null)
217
+ if (finding.tip !== null) {
208
218
  lines.push(`${marked ? ' ' : ''} tip: ${finding.tip}`);
219
+ }
209
220
  }
210
221
  if (report.instructions.length > 0) {
211
222
  lines.push('', 'PHPStan adds:');
212
- for (const regel of report.instructions)
223
+ for (const regel of report.instructions) {
213
224
  lines.push(` ${regel}`);
225
+ }
214
226
  }
215
227
  if (report.page.hasMore) {
216
228
  lines.push('', runId === undefined
@@ -225,12 +237,15 @@ export function renderReport(report, runId) {
225
237
  /** Waarop de pagina beperkt is, als bijzin ("with identifier x on a changed line"), of null. */
226
238
  function describeFilters(report) {
227
239
  const parts = [];
228
- if (report.filter !== null)
240
+ if (report.filter !== null) {
229
241
  parts.push(`with identifier ${report.filter.join(', ')}`);
230
- if (report.onlyIn !== null)
242
+ }
243
+ if (report.onlyIn !== null) {
231
244
  parts.push(`in ${report.onlyIn.join(', ')}`);
232
- if (report.changedLines?.onlyChangedLines === true)
245
+ }
246
+ if (report.changedLines?.onlyChangedLines === true) {
233
247
  parts.push('on a changed line');
248
+ }
234
249
  return parts.length === 0 ? null : parts.join(' ');
235
250
  }
236
251
  /**
@@ -243,8 +258,9 @@ function describeChangedLines(changes, comparedWithBase = false) {
243
258
  const zin = `${changes.onChangedLine} on a line you changed (marked with +), ` +
244
259
  `${changes.elsewhere} elsewhere in the changed files, ${changes.otherFiles} in files you did not change.`;
245
260
  // Met het "vóór" is het voorbehoud niet meer nodig: de vergelijking erboven zegt het.
246
- if (comparedWithBase)
261
+ if (comparedWithBase) {
247
262
  return `${zin} The comparison above says which of them your change introduced.`;
263
+ }
248
264
  // Het voorbehoud is hier nog zwaarder: in een project zonder baseline staan alle oude
249
265
  // fouten onder "not changed". Welke door de wijziging komen, zegt één analyse niet.
250
266
  return changes.otherFiles === 0 && changes.elsewhere === 0
@@ -277,13 +293,15 @@ function describeComparison(comparison) {
277
293
  ];
278
294
  if (comparison.fixedFindings.length > 0) {
279
295
  lines.push(comparison.basis === 'base' ? 'Fixed (line numbers from before your change):' : 'Fixed (line numbers from that analysis):', ...comparison.fixedFindings.map(comparedLine));
280
- if (comparison.omitted.fixed > 0)
296
+ if (comparison.omitted.fixed > 0) {
281
297
  lines.push(` (and ${String(comparison.omitted.fixed)} more)`);
298
+ }
282
299
  }
283
300
  if (comparison.newFindings.length > 0) {
284
301
  lines.push('New:', ...comparison.newFindings.map(comparedLine));
285
- if (comparison.omitted.new > 0)
302
+ if (comparison.omitted.new > 0) {
286
303
  lines.push(` (and ${String(comparison.omitted.new)} more)`);
304
+ }
287
305
  }
288
306
  if (comparison.notCompared.findings > 0) {
289
307
  lines.push(`${String(comparison.notCompared.findings)} finding(s) are in files that only one of the two analyses ` +
@@ -388,8 +406,9 @@ function topRows(counts) {
388
406
  */
389
407
  export function displayPath(project, file) {
390
408
  const rel = relative(project, file);
391
- if (rel === '' || rel.startsWith('..') || isAbsolute(rel))
409
+ if (rel === '' || rel.startsWith('..') || isAbsolute(rel)) {
392
410
  return file;
411
+ }
393
412
  return rel;
394
413
  }
395
414
  function clamp(value, low, high) {