phpstan-mcp-mx 0.23.0 → 0.25.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.
- package/CHANGELOG.md +29 -0
- package/README.md +146 -2
- package/dist/baseline.d.ts +10 -0
- package/dist/baseline.js +13 -3
- package/dist/baseline.js.map +1 -1
- package/dist/changed.d.ts +17 -0
- package/dist/changed.js +4 -3
- package/dist/changed.js.map +1 -1
- package/dist/config.js +4 -2
- package/dist/config.js.map +1 -1
- package/dist/dumptype.d.ts +2 -0
- package/dist/dumptype.js +26 -4
- package/dist/dumptype.js.map +1 -1
- package/dist/failure.d.ts +1 -1
- package/dist/failure.js.map +1 -1
- package/dist/finding.d.ts +65 -0
- package/dist/finding.js +177 -0
- package/dist/finding.js.map +1 -0
- package/dist/history.d.ts +61 -0
- package/dist/history.js +275 -0
- package/dist/history.js.map +1 -0
- package/dist/phpstan/process.d.ts +10 -0
- package/dist/phpstan/process.js +12 -0
- package/dist/phpstan/process.js.map +1 -1
- package/dist/phpstan.d.ts +14 -0
- package/dist/phpstan.js +70 -13
- package/dist/phpstan.js.map +1 -1
- package/dist/prune.d.ts +92 -0
- package/dist/prune.js +387 -0
- package/dist/prune.js.map +1 -0
- package/dist/tools/inspect.d.ts +4 -0
- package/dist/tools/inspect.js +135 -3
- package/dist/tools/inspect.js.map +1 -1
- package/dist/tools/prompts.js +13 -5
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/writes.d.ts +5 -0
- package/dist/tools/writes.js +70 -0
- package/dist/tools/writes.js.map +1 -1
- package/dist/tools.js +5 -2
- package/dist/tools.js.map +1 -1
- package/dist/unmatched.d.ts +66 -0
- package/dist/unmatched.js +166 -31
- package/dist/unmatched.js.map +1 -1
- package/package.json +1 -1
package/dist/failure.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failure.js","sourceRoot":"","sources":["../src/failure.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"failure.js","sourceRoot":"","sources":["../src/failure.ts"],"names":[],"mappings":"AA+DA;;;;;GAKG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACE;IAAgC;IAAtE,YAAY,OAAe,EAAW,MAAqB,EAAW,UAA0B,EAAE;QAEhG,KAAK,CAAC,OAAO,CAAC,CAAC;QAFqB,WAAM,GAAN,MAAM,CAAe;QAAW,YAAO,GAAP,OAAO,CAAqB;IAGlG,CAAC;CACF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ParseProblem, ProbedType } from './dumptype.js';
|
|
2
|
+
import type { AnalyseOptions } from './phpstan.js';
|
|
3
|
+
import type { ResolvedProject } from './project.js';
|
|
4
|
+
/** Hoeveel regels er standaard voor en na de regel getoond worden. */
|
|
5
|
+
export declare const DEFAULT_CONTEXT = 5;
|
|
6
|
+
/** Meer is geen context meer maar het bestand; dat hoort bij een tool die het bestand leest. */
|
|
7
|
+
export declare const MAX_CONTEXT = 30;
|
|
8
|
+
/** Wat een aanroep vraagt. */
|
|
9
|
+
export interface FindingRequest {
|
|
10
|
+
readonly path: string;
|
|
11
|
+
readonly line: number;
|
|
12
|
+
readonly context?: number | undefined;
|
|
13
|
+
/** Zonder: de variabelen en property-ketens op de regel zelf. */
|
|
14
|
+
readonly expressions?: readonly string[] | undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Een bevinding van PHPStan op de gevraagde regel, uit dezelfde run als de types. */
|
|
17
|
+
export interface LineFinding {
|
|
18
|
+
readonly message: string;
|
|
19
|
+
readonly identifier: string | null;
|
|
20
|
+
readonly tip: string | null;
|
|
21
|
+
}
|
|
22
|
+
/** Het antwoord van `show_finding`. */
|
|
23
|
+
export interface FindingView {
|
|
24
|
+
readonly project: string;
|
|
25
|
+
/** Pad relatief aan de projectroot. */
|
|
26
|
+
readonly file: string;
|
|
27
|
+
readonly line: number;
|
|
28
|
+
/** De code rond de regel, met de regelnummers van het bestand. */
|
|
29
|
+
readonly code: readonly {
|
|
30
|
+
number: number;
|
|
31
|
+
text: string;
|
|
32
|
+
}[];
|
|
33
|
+
/** Wat PHPStan op deze regel meldt; null als PHPStan niet gestart is of het bestand niet kon lezen. */
|
|
34
|
+
readonly findings: readonly LineFinding[] | null;
|
|
35
|
+
readonly types: readonly ProbedType[];
|
|
36
|
+
/** Waarom er geen types zijn, of null als ze er zijn. */
|
|
37
|
+
readonly typesProblem: string | null;
|
|
38
|
+
readonly parseErrors: readonly ParseProblem[];
|
|
39
|
+
readonly generalErrors: readonly string[];
|
|
40
|
+
readonly warnings: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Een bevinding met de code eromheen en de types die PHPStan vlak vóór die regel afleidt.
|
|
44
|
+
*
|
|
45
|
+
* Voor een client die zelf geen bestanden kan lezen (Claude Desktop): daar ziet het model
|
|
46
|
+
* van een bevinding alleen de melding. In Claude Code kan het model het bestand zelf openen,
|
|
47
|
+
* maar de types niet zien; die komen uit hetzelfde mechanisme als `inspect_type`, een kopie
|
|
48
|
+
* in editor mode, en dezelfde run levert de bevindingen op die regel.
|
|
49
|
+
*
|
|
50
|
+
* Staat er op de regel geen variabele, dan start PHPStan niet: er valt niets te dumpen, en de
|
|
51
|
+
* melding had het model al. Is de regel geen begin van een statement, dan geeft PHPStan een
|
|
52
|
+
* parse-fout; die wordt benoemd, en er wordt niet naar een andere regel gegokt.
|
|
53
|
+
*/
|
|
54
|
+
export declare function showFinding(project: ResolvedProject, request: FindingRequest, options?: Pick<AnalyseOptions, 'config' | 'memoryLimit' | 'timeoutMs' | 'signal'>): Promise<FindingView>;
|
|
55
|
+
/**
|
|
56
|
+
* De variabelen en property-ketens op een regel, zoals ze vóór die regel al bestaan: `$user`,
|
|
57
|
+
* `$this->repo`, `$order->customer->email`. Geen methode-aanroepen (daar horen argumenten bij),
|
|
58
|
+
* geen kale `$this` (dat is de klasse), en niets wat pas op deze regel ontstaat: het doel van
|
|
59
|
+
* een toewijzing, de variabelen van een `foreach … as` en de parameters van een closure. Die
|
|
60
|
+
* geven vóór de regel alleen `*ERROR*`. Een tekst tussen enkele quotes en commentaar tellen niet
|
|
61
|
+
* mee; tussen dubbele quotes wel, want daar wordt een variabele ingevuld.
|
|
62
|
+
*/
|
|
63
|
+
export declare function variablesOn(line: string): string[];
|
|
64
|
+
/** Schrijft de bevinding uit als tekst voor het model. */
|
|
65
|
+
export declare function renderFinding(view: FindingView): string;
|
package/dist/finding.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { MAX_EXPRESSIONS, insertProbes, readProbes } from './dumptype.js';
|
|
3
|
+
import { PhpstanError, analyseEdited, tmpCopyName } from './phpstan.js';
|
|
4
|
+
import { resolveWithin } from './project.js';
|
|
5
|
+
import { displayPath } from './report.js';
|
|
6
|
+
/** Hoeveel regels er standaard voor en na de regel getoond worden. */
|
|
7
|
+
export const DEFAULT_CONTEXT = 5;
|
|
8
|
+
/** Meer is geen context meer maar het bestand; dat hoort bij een tool die het bestand leest. */
|
|
9
|
+
export const MAX_CONTEXT = 30;
|
|
10
|
+
/** Een regel code wordt ingekort; een geminificeerd bestand heeft er één van een megabyte. */
|
|
11
|
+
const MAX_LINE_CHARS = 300;
|
|
12
|
+
/**
|
|
13
|
+
* Een bevinding met de code eromheen en de types die PHPStan vlak vóór die regel afleidt.
|
|
14
|
+
*
|
|
15
|
+
* Voor een client die zelf geen bestanden kan lezen (Claude Desktop): daar ziet het model
|
|
16
|
+
* van een bevinding alleen de melding. In Claude Code kan het model het bestand zelf openen,
|
|
17
|
+
* maar de types niet zien; die komen uit hetzelfde mechanisme als `inspect_type`, een kopie
|
|
18
|
+
* in editor mode, en dezelfde run levert de bevindingen op die regel.
|
|
19
|
+
*
|
|
20
|
+
* Staat er op de regel geen variabele, dan start PHPStan niet: er valt niets te dumpen, en de
|
|
21
|
+
* melding had het model al. Is de regel geen begin van een statement, dan geeft PHPStan een
|
|
22
|
+
* parse-fout; die wordt benoemd, en er wordt niet naar een andere regel gegokt.
|
|
23
|
+
*/
|
|
24
|
+
export async function showFinding(project, request, options = {}) {
|
|
25
|
+
const file = resolveWithin(project, request.path);
|
|
26
|
+
if (!statSync(file).isFile()) {
|
|
27
|
+
throw new PhpstanError(`"${request.path}" is a directory; show_finding needs one PHP file.`, 'invalid_argument', {
|
|
28
|
+
hint: 'Pass the path of the file the finding is in.',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const source = readFileSync(file, 'utf8');
|
|
32
|
+
const lines = source.split('\n').map((line) => line.replace(/\r$/, ''));
|
|
33
|
+
// Een afsluitend regeleinde levert een lege laatste "regel" op die in geen editor bestaat.
|
|
34
|
+
const count = source.endsWith('\n') ? lines.length - 1 : lines.length;
|
|
35
|
+
if (!Number.isInteger(request.line) || request.line < 1 || request.line > count) {
|
|
36
|
+
throw new PhpstanError(`Line ${String(request.line)} is outside the file, which has ${String(count)} line(s).`, 'invalid_argument', {
|
|
37
|
+
hint: 'Pass the line from the finding.',
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const context = Math.min(Math.max(Math.trunc(request.context ?? DEFAULT_CONTEXT), 0), MAX_CONTEXT);
|
|
41
|
+
const from = Math.max(request.line - context, 1);
|
|
42
|
+
const to = Math.min(request.line + context, count);
|
|
43
|
+
const code = lines.slice(from - 1, to).map((text, index) => ({ number: from + index, text: shorten(text) }));
|
|
44
|
+
const base = { project: project.path, file: displayPath(project.path, file), line: request.line, code };
|
|
45
|
+
const expressions = request.expressions ?? variablesOn(lines[request.line - 1] ?? '');
|
|
46
|
+
if (expressions.length === 0) {
|
|
47
|
+
return {
|
|
48
|
+
...base,
|
|
49
|
+
findings: null,
|
|
50
|
+
types: [],
|
|
51
|
+
typesProblem: 'There is no variable on this line, so PHPStan was not started. Pass expressions to see their types.',
|
|
52
|
+
parseErrors: [],
|
|
53
|
+
generalErrors: [],
|
|
54
|
+
warnings: [],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const probe = insertProbes(source, request.line, expressions);
|
|
58
|
+
const result = await analyseEdited(project, { insteadOf: file, content: probe.content, name: tmpCopyName(project.path, 'finding') }, options);
|
|
59
|
+
const report = readProbes(project.path, file, probe, result);
|
|
60
|
+
// Na het invoegen staat de gevraagde regel zoveel regels lager als er dumps zijn.
|
|
61
|
+
const verschoven = request.line + probe.expressions.length;
|
|
62
|
+
const findings = result.findings
|
|
63
|
+
.filter((finding) => finding.file === file && finding.line === verschoven && finding.identifier !== 'phpstan.parse')
|
|
64
|
+
.map((finding) => ({ message: finding.message, identifier: finding.identifier, tip: finding.tip }));
|
|
65
|
+
if (report.parseErrors.length > 0) {
|
|
66
|
+
return {
|
|
67
|
+
...base,
|
|
68
|
+
findings: null,
|
|
69
|
+
types: [],
|
|
70
|
+
typesProblem: `Line ${String(request.line)} does not start a statement (it is, for example, inside an array or a method ` +
|
|
71
|
+
'chain that spans several lines), so nothing can be inserted before it. Call inspect_type with the line ' +
|
|
72
|
+
'where the statement starts.',
|
|
73
|
+
parseErrors: report.parseErrors,
|
|
74
|
+
generalErrors: report.generalErrors,
|
|
75
|
+
warnings: report.warnings,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
...base,
|
|
80
|
+
findings,
|
|
81
|
+
types: report.types,
|
|
82
|
+
typesProblem: null,
|
|
83
|
+
parseErrors: [],
|
|
84
|
+
generalErrors: report.generalErrors,
|
|
85
|
+
warnings: report.warnings,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* De variabelen en property-ketens op een regel, zoals ze vóór die regel al bestaan: `$user`,
|
|
90
|
+
* `$this->repo`, `$order->customer->email`. Geen methode-aanroepen (daar horen argumenten bij),
|
|
91
|
+
* geen kale `$this` (dat is de klasse), en niets wat pas op deze regel ontstaat: het doel van
|
|
92
|
+
* een toewijzing, de variabelen van een `foreach … as` en de parameters van een closure. Die
|
|
93
|
+
* geven vóór de regel alleen `*ERROR*`. Een tekst tussen enkele quotes en commentaar tellen niet
|
|
94
|
+
* mee; tussen dubbele quotes wel, want daar wordt een variabele ingevuld.
|
|
95
|
+
*/
|
|
96
|
+
export function variablesOn(line) {
|
|
97
|
+
const code = line
|
|
98
|
+
.replace(/'(?:[^'\\]|\\.)*'/g, "''")
|
|
99
|
+
.replace(/\/\*.*?\*\//g, '')
|
|
100
|
+
.replace(/(?:\/\/|#(?!\[)).*$/, '');
|
|
101
|
+
const nieuw = new Set();
|
|
102
|
+
for (const match of code.matchAll(/(\$\w+)\s*(?:=(?![=>])|\?\?=)/g)) {
|
|
103
|
+
// `??=` laat een bestaande waarde staan, maar de variabele hoeft nog niet te bestaan.
|
|
104
|
+
nieuw.add(match[1] ?? '');
|
|
105
|
+
}
|
|
106
|
+
for (const match of code.matchAll(/\bas\s+(?:&?\s*(\$\w+)\s*=>\s*)?&?\s*(\$\w+)/g)) {
|
|
107
|
+
nieuw.add(match[1] ?? '');
|
|
108
|
+
nieuw.add(match[2] ?? '');
|
|
109
|
+
}
|
|
110
|
+
for (const match of code.matchAll(/\b(?:fn|function)\s*&?\s*\(([^)]*)\)/g)) {
|
|
111
|
+
for (const parameter of (match[1] ?? '').matchAll(/\$\w+/g)) {
|
|
112
|
+
nieuw.add(parameter[0]);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const gevonden = [];
|
|
116
|
+
// `(?!\w)` vóór de lookahead op `(`: anders maakt backtracking van `$a->foo()` een `$a->fo`.
|
|
117
|
+
// Niet na `::`: `self::$x` is een statische property, geen lokale variabele.
|
|
118
|
+
for (const match of code.matchAll(/(?<!::)\$\w+(?:\s*\??->\s*\w+(?!\w)(?!\s*\())*/g)) {
|
|
119
|
+
const expressie = match[0].replace(/\s+/g, '');
|
|
120
|
+
const variabele = /^\$\w+/.exec(expressie)?.[0] ?? '';
|
|
121
|
+
if (expressie === '$this' || nieuw.has(variabele) || gevonden.includes(expressie)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
gevonden.push(expressie);
|
|
125
|
+
}
|
|
126
|
+
return gevonden.slice(0, MAX_EXPRESSIONS);
|
|
127
|
+
}
|
|
128
|
+
/** Schrijft de bevinding uit als tekst voor het model. */
|
|
129
|
+
export function renderFinding(view) {
|
|
130
|
+
const lines = [`${view.file}, line ${String(view.line)}:`, ''];
|
|
131
|
+
const breedte = String(view.code.at(-1)?.number ?? view.line).length;
|
|
132
|
+
for (const regel of view.code) {
|
|
133
|
+
const teken = regel.number === view.line ? '>' : ' ';
|
|
134
|
+
lines.push(`${teken} ${String(regel.number).padStart(breedte)} | ${regel.text}`.trimEnd());
|
|
135
|
+
}
|
|
136
|
+
if (view.warnings.length > 0) {
|
|
137
|
+
lines.push('', 'WARNING PHPStan reported this alongside the result:', ...view.warnings.map((warning) => `- ${warning}`));
|
|
138
|
+
}
|
|
139
|
+
if (view.generalErrors.length > 0) {
|
|
140
|
+
lines.push('', 'Errors not tied to a file:', ...view.generalErrors.map((error) => `- ${error}`));
|
|
141
|
+
}
|
|
142
|
+
if (view.findings !== null) {
|
|
143
|
+
lines.push('');
|
|
144
|
+
if (view.findings.length === 0) {
|
|
145
|
+
lines.push('PHPStan reports nothing on this line.');
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
lines.push('PHPStan reports on this line:');
|
|
149
|
+
for (const finding of view.findings) {
|
|
150
|
+
lines.push(`- ${finding.identifier === null ? '' : `${finding.identifier}: `}${finding.message}`);
|
|
151
|
+
if (finding.tip !== null) {
|
|
152
|
+
lines.push(` tip: ${finding.tip}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
lines.push('');
|
|
158
|
+
if (view.typesProblem !== null) {
|
|
159
|
+
lines.push(`No types: ${view.typesProblem}`);
|
|
160
|
+
for (const error of view.parseErrors) {
|
|
161
|
+
lines.push(`- ${error.inserted ? 'inserted line' : error.line === null ? 'no line' : `line ${String(error.line)}`}: ${error.message}`);
|
|
162
|
+
}
|
|
163
|
+
return lines.join('\n');
|
|
164
|
+
}
|
|
165
|
+
lines.push(`Types right before line ${String(view.line)}:`);
|
|
166
|
+
for (const probed of view.types) {
|
|
167
|
+
lines.push(`- ${probed.expression}: ${probed.type ?? 'no type reported'}`);
|
|
168
|
+
for (const problem of probed.problems) {
|
|
169
|
+
lines.push(` ${problem.identifier === null ? '' : `${problem.identifier}: `}${problem.message}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return lines.join('\n');
|
|
173
|
+
}
|
|
174
|
+
function shorten(text) {
|
|
175
|
+
return text.length <= MAX_LINE_CHARS ? text : `${text.slice(0, MAX_LINE_CHARS)}… (line cut off)`;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=finding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding.js","sourceRoot":"","sources":["../src/finding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAExE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,sEAAsE;AACtE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAEjC,gGAAgG;AAChG,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAE9B,8FAA8F;AAC9F,MAAM,cAAc,GAAG,GAAG,CAAC;AAoC3B;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAwB,EACxB,OAAuB,EACvB,UAAmF,EAAE;IAGrF,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAElD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,oDAAoD,EAAE,kBAAkB,EAAE;YAC/G,IAAI,EAAE,8CAA8C;SACrD,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IACxE,2FAA2F;IAC3F,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IAEtE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC;QAChF,MAAM,IAAI,YAAY,CAAC,QAAQ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,mCAAmC,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,kBAAkB,EAAE;YAClI,IAAI,EAAE,iCAAiC;SACxC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACnG,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC;IACjD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO,EAAE,KAAK,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAE7G,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACxG,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAEtF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO;YACL,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,EAAE;YACT,YAAY,EAAE,qGAAqG;YACnH,WAAW,EAAE,EAAE;YACf,aAAa,EAAE,EAAE;YACjB,QAAQ,EAAE,EAAE;SACb,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAC9I,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAE7D,kFAAkF;IAClF,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC;IAC3D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ;SAC7B,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,CAAC,UAAU,KAAK,eAAe,CAAC;SACnH,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAEtG,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO;YACL,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,EAAE;YACT,YAAY,EACV,QAAQ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,+EAA+E;gBAC3G,yGAAyG;gBACzG,6BAA6B;YAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAC;IACJ,CAAC;IAED,OAAO;QACL,GAAG,IAAI;QACP,QAAQ;QACR,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,YAAY,EAAE,IAAI;QAClB,WAAW,EAAE,EAAE;QACf,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IAEtC,MAAM,IAAI,GAAG,IAAI;SACd,OAAO,CAAC,oBAAoB,EAAE,IAAI,CAAC;SACnC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;SAC3B,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC;IAEtC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,gCAAgC,CAAC,EAAE,CAAC;QACpE,sFAAsF;QACtF,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,+CAA+C,CAAC,EAAE,CAAC;QACnF,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1B,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,uCAAuC,CAAC,EAAE,CAAC;QAC3E,KAAK,MAAM,SAAS,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5D,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,6FAA6F;IAC7F,6EAA6E;IAC7E,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,iDAAiD,CAAC,EAAE,CAAC;QACrF,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEtD,IAAI,SAAS,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAClF,SAAS;QACX,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;AAC5C,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,aAAa,CAAC,IAAiB;IAE7C,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,UAAU,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IAErE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACrD,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,qDAAqD,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3H,CAAC;IAED,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,4BAA4B,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC;IACnG,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEf,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YAE5C,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACpC,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBAElG,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC;oBACzB,KAAK,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;gBACtC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QAE7C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACzI,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE5D,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI,kBAAkB,EAAE,CAAC,CAAC;QAE3E,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACtG,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,OAAO,CAAC,IAAY;IAE3B,OAAO,IAAI,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,kBAAkB,CAAC;AACnG,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ResolvedProject } from './project.js';
|
|
2
|
+
/** Hoeveel wijzigingen per baseline-bestand standaard. */
|
|
3
|
+
export declare const DEFAULT_HISTORY_LIMIT = 20;
|
|
4
|
+
/** Meer dan dit is niet meer te lezen, en elke wijziging kost een `git show`. */
|
|
5
|
+
export declare const MAX_HISTORY_LIMIT = 100;
|
|
6
|
+
/** Hoeveel entries en genegeerde fouten een baseline telt. */
|
|
7
|
+
export interface BaselineCount {
|
|
8
|
+
readonly entries: number;
|
|
9
|
+
readonly errors: number;
|
|
10
|
+
}
|
|
11
|
+
/** Eén wijziging van een baseline-bestand, of de werkkopie als die afwijkt van de laatste commit. */
|
|
12
|
+
export interface HistoryRow {
|
|
13
|
+
/** Null: de werkkopie, nog niet gecommit. */
|
|
14
|
+
readonly commit: string | null;
|
|
15
|
+
/** Commitdatum, ISO 8601; null bij de werkkopie. */
|
|
16
|
+
readonly date: string | null;
|
|
17
|
+
readonly subject: string | null;
|
|
18
|
+
/** De naam van het bestand in die commit; anders dan nu als het later hernoemd is. */
|
|
19
|
+
readonly file: string;
|
|
20
|
+
/** Null als het bestand in die commit niet te lezen was. */
|
|
21
|
+
readonly count: BaselineCount | null;
|
|
22
|
+
/** Ten opzichte van de rij eronder; null als een van beide niet te lezen was. */
|
|
23
|
+
readonly delta: BaselineCount | null;
|
|
24
|
+
/** De soorten die het meest veranderden, in genegeerde fouten; positief is erbij. */
|
|
25
|
+
readonly changes: readonly {
|
|
26
|
+
identifier: string;
|
|
27
|
+
change: number;
|
|
28
|
+
}[];
|
|
29
|
+
}
|
|
30
|
+
/** Het verloop van één baseline-bestand, nieuwste wijziging eerst. */
|
|
31
|
+
export interface FileHistory {
|
|
32
|
+
readonly file: string;
|
|
33
|
+
readonly rows: readonly HistoryRow[];
|
|
34
|
+
/** De stand vóór de oudste rij: nul als het bestand daar ontstond. */
|
|
35
|
+
readonly start: BaselineCount | null;
|
|
36
|
+
/** Of er nog oudere commits zijn die het bestand raakten; dan helpt een hogere `limit`. */
|
|
37
|
+
readonly olderCommits: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Het antwoord van `baseline_history`. */
|
|
40
|
+
export interface HistoryReport {
|
|
41
|
+
readonly project: string;
|
|
42
|
+
readonly files: readonly FileHistory[];
|
|
43
|
+
readonly notices: readonly string[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Het verloop van de geïncludeerde baselines door de git-geschiedenis: per commit die het
|
|
47
|
+
* bestand raakte hoeveel entries en genegeerde fouten, het verschil met de vorige, en welke
|
|
48
|
+
* soorten het meest veranderden. Zonder PHPStan: alleen git en de baseline-parser.
|
|
49
|
+
*
|
|
50
|
+
* Langs de first-parent-lijn van HEAD, want alleen dan is "het verschil met de rij eronder"
|
|
51
|
+
* zinvol: zonder die vlag komen commits uit verschillende branches op datum door elkaar, en
|
|
52
|
+
* vergelijk je een commit met een die er nooit zijn ouder was. Een gemergede branch telt zo als
|
|
53
|
+
* één wijziging, en dat is ook de vraag: welke merge zette er een stapel bij. `--follow`, zodat
|
|
54
|
+
* een hernoemd bestand niet begint met "alles nieuw"; dat kan alleen per bestand.
|
|
55
|
+
*
|
|
56
|
+
* Bewust zonder auteur: commit en onderwerp zijn genoeg om hem terug te vinden, en een lijst
|
|
57
|
+
* met namen bij "wie zette er fouten bij" is niet waar deze tool voor is.
|
|
58
|
+
*/
|
|
59
|
+
export declare function baselineHistory(project: ResolvedProject, limit?: number): Promise<HistoryReport>;
|
|
60
|
+
/** Schrijft het verloop uit als tekst voor het model. */
|
|
61
|
+
export declare function renderHistory(report: HistoryReport): string;
|
package/dist/history.js
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { findBaselineFiles, includedBaselineFiles, isUnreadableBaseline, parseBaseline } from './baseline.js';
|
|
4
|
+
import { GitError, execute, gitShow, throwIfFailed } from './changed.js';
|
|
5
|
+
/** Hoeveel wijzigingen per baseline-bestand standaard. */
|
|
6
|
+
export const DEFAULT_HISTORY_LIMIT = 20;
|
|
7
|
+
/** Meer dan dit is niet meer te lezen, en elke wijziging kost een `git show`. */
|
|
8
|
+
export const MAX_HISTORY_LIMIT = 100;
|
|
9
|
+
/** Hoeveel soorten een rij hoogstens noemt bij "wat veranderde er". */
|
|
10
|
+
const CHANGE_ROWS = 4;
|
|
11
|
+
/** Scheiding tussen commits en tussen velden in de uitvoer van `git log`; komen niet voor in een onderwerp. */
|
|
12
|
+
const RECORD = '\x1e';
|
|
13
|
+
const FIELD = '\x1f';
|
|
14
|
+
const EMPTY = { count: { entries: 0, errors: 0 }, entries: [] };
|
|
15
|
+
/**
|
|
16
|
+
* Het verloop van de geïncludeerde baselines door de git-geschiedenis: per commit die het
|
|
17
|
+
* bestand raakte hoeveel entries en genegeerde fouten, het verschil met de vorige, en welke
|
|
18
|
+
* soorten het meest veranderden. Zonder PHPStan: alleen git en de baseline-parser.
|
|
19
|
+
*
|
|
20
|
+
* Langs de first-parent-lijn van HEAD, want alleen dan is "het verschil met de rij eronder"
|
|
21
|
+
* zinvol: zonder die vlag komen commits uit verschillende branches op datum door elkaar, en
|
|
22
|
+
* vergelijk je een commit met een die er nooit zijn ouder was. Een gemergede branch telt zo als
|
|
23
|
+
* één wijziging, en dat is ook de vraag: welke merge zette er een stapel bij. `--follow`, zodat
|
|
24
|
+
* een hernoemd bestand niet begint met "alles nieuw"; dat kan alleen per bestand.
|
|
25
|
+
*
|
|
26
|
+
* Bewust zonder auteur: commit en onderwerp zijn genoeg om hem terug te vinden, en een lijst
|
|
27
|
+
* met namen bij "wie zette er fouten bij" is niet waar deze tool voor is.
|
|
28
|
+
*/
|
|
29
|
+
export async function baselineHistory(project, limit = DEFAULT_HISTORY_LIMIT) {
|
|
30
|
+
const files = includedBaselineFiles(project);
|
|
31
|
+
if (files.length === 0) {
|
|
32
|
+
return { project: project.path, files: [], notices: [noBaselineNotice(project)] };
|
|
33
|
+
}
|
|
34
|
+
const { prefix, shallow } = await repository(project);
|
|
35
|
+
const max = Math.min(Math.max(Math.trunc(limit), 1), MAX_HISTORY_LIMIT);
|
|
36
|
+
const histories = [];
|
|
37
|
+
for (const file of files) {
|
|
38
|
+
histories.push(await historyOf(project, prefix, file, max));
|
|
39
|
+
}
|
|
40
|
+
const notices = [];
|
|
41
|
+
if (shallow) {
|
|
42
|
+
notices.push('This is a shallow clone: git has only part of the history, so the oldest change shown may be counted as ' +
|
|
43
|
+
'the creation of the baseline while it is not.');
|
|
44
|
+
}
|
|
45
|
+
const onleesbaar = histories.flatMap((history) => history.rows.filter((row) => row.count === null).map((row) => `${history.file} at ${row.commit ?? 'the working copy'}`));
|
|
46
|
+
if (onleesbaar.length > 0) {
|
|
47
|
+
notices.push(`Could not read the baseline in: ${onleesbaar.join(', ')}. Its counts and the change next to it are unknown, not zero.`);
|
|
48
|
+
}
|
|
49
|
+
return { project: project.path, files: histories, notices };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Het pad van het project binnen de repository, en of het een ondiepe kloon is. In één
|
|
53
|
+
* aanroep, die tegelijk zegt of er überhaupt een repository is.
|
|
54
|
+
*/
|
|
55
|
+
async function repository(project) {
|
|
56
|
+
const args = ['rev-parse', '--show-prefix', '--is-shallow-repository'];
|
|
57
|
+
const result = await execute(project.path, args);
|
|
58
|
+
try {
|
|
59
|
+
throwIfFailed(project.path, args, result);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
throw explain(project, error);
|
|
63
|
+
}
|
|
64
|
+
const [prefix = '', shallow = ''] = result.stdout.split('\n').map((line) => line.trim());
|
|
65
|
+
return { prefix, shallow: shallow === 'true' };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Een eigen melding bij een ontbrekende git of repository: die van `throwIfFailed` is
|
|
69
|
+
* geschreven voor `analyse_changed` en raadt `analyse_project` met paden aan, en dat helpt hier
|
|
70
|
+
* niet. Een fout en geen lege uitkomst: de geschiedenis is hier het hele antwoord, en "niets"
|
|
71
|
+
* zou lezen als een baseline die nooit veranderd is.
|
|
72
|
+
*/
|
|
73
|
+
function explain(project, error) {
|
|
74
|
+
if (!(error instanceof GitError)) {
|
|
75
|
+
return error;
|
|
76
|
+
}
|
|
77
|
+
if (error.reason === 'not_a_git_repository') {
|
|
78
|
+
return new GitError(`${project.path} is not under git, so its baseline has no history to read. baseline_summary shows what is in it now.`, error.reason, error.details);
|
|
79
|
+
}
|
|
80
|
+
if (error.reason === 'git_missing' && /not found/i.test(error.message)) {
|
|
81
|
+
return new GitError('git was not found, and the history of the baseline is read with git. baseline_summary works without it.', error.reason, error.details);
|
|
82
|
+
}
|
|
83
|
+
return error;
|
|
84
|
+
}
|
|
85
|
+
async function historyOf(project, prefix, file, limit) {
|
|
86
|
+
// Eén commit meer dan getoond: dat is de stand vóór de oudste rij. Is die er niet, dan
|
|
87
|
+
// ontstond het bestand in de oudste rij.
|
|
88
|
+
const logged = await logOf(project, file, `${prefix}${file}`, limit + 1);
|
|
89
|
+
const shown = logged.slice(0, limit);
|
|
90
|
+
const older = logged[limit];
|
|
91
|
+
const snapshots = [];
|
|
92
|
+
for (const commit of shown) {
|
|
93
|
+
snapshots.push(snapshot(await gitShow(project.path, `${commit.commit}:${commit.path}`)));
|
|
94
|
+
}
|
|
95
|
+
const start = older === undefined ? EMPTY : snapshot(await gitShow(project.path, `${older.commit}:${older.path}`));
|
|
96
|
+
const rows = shown.map((commit, index) => {
|
|
97
|
+
const before = snapshots[index + 1] ?? start;
|
|
98
|
+
return row(commit.commit, commit.date, commit.subject, display(commit.path, prefix), snapshots[index] ?? EMPTY, before);
|
|
99
|
+
});
|
|
100
|
+
// De werkkopie, als die afwijkt van de laatste commit. Vergeleken op de entries en niet op
|
|
101
|
+
// de tekst: met core.autocrlf verschillen de regeleinden, en dat is geen wijziging.
|
|
102
|
+
const working = snapshot(readOrEmpty(join(project.path, file)));
|
|
103
|
+
const latest = snapshots[0] ?? start;
|
|
104
|
+
if (shown.length === 0 || !sameEntries(working, latest)) {
|
|
105
|
+
rows.unshift(row(null, null, null, file, working, latest));
|
|
106
|
+
}
|
|
107
|
+
return { file, rows, start: start.count, olderCommits: older !== undefined };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* De commits die dit bestand raakten, nieuwste eerst. Een lege repository is geen fout: dan is
|
|
111
|
+
* er nog geen geschiedenis, en is de werkkopie het hele verhaal.
|
|
112
|
+
*
|
|
113
|
+
* `--no-color`, `--no-ext-diff` en `--no-show-signature` zetten vast wat de gebruikersconfig
|
|
114
|
+
* anders verandert aan uitvoer die geparsed wordt, net als bij `diff -U0` en `git grep`: met
|
|
115
|
+
* `log.showSignature=true` staat de GPG-uitvoer tussen de regels. Het pad staat na `--` en
|
|
116
|
+
* komt uit de map van het project (een naam die met `phpstan-baseline` begint), niet uit een
|
|
117
|
+
* aanroep.
|
|
118
|
+
*
|
|
119
|
+
* Twee paden, want git is hier niet consequent: de pathspec geldt vanaf de werkmap (het
|
|
120
|
+
* project), de namen die `--name-only` teruggeeft gelden vanaf de repositoryroot. Met één pad
|
|
121
|
+
* vond de test voor een project in een submap niets.
|
|
122
|
+
*/
|
|
123
|
+
async function logOf(project, pathspec, fromRoot, max) {
|
|
124
|
+
const args = [
|
|
125
|
+
'log', '--first-parent', '--follow', '--no-color', '--no-ext-diff', '--no-show-signature', '--name-only',
|
|
126
|
+
`--format=${RECORD}%H${FIELD}%cI${FIELD}%s`, `--max-count=${String(max)}`, '--', pathspec,
|
|
127
|
+
];
|
|
128
|
+
const result = await execute(project.path, args);
|
|
129
|
+
if (result.spawnError === null && result.code !== 0 && /does not have any commits yet|bad default revision/i.test(result.stderr)) {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
throwIfFailed(project.path, args, result);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
throw explain(project, error);
|
|
137
|
+
}
|
|
138
|
+
const commits = [];
|
|
139
|
+
// Van nieuw naar oud: het pad van een commit waar git geen naam bij geeft (een merge op een
|
|
140
|
+
// oude git, die de first-parent-diff nog niet toont), is dat van de rij erboven.
|
|
141
|
+
let current = fromRoot;
|
|
142
|
+
for (const record of result.stdout.split(RECORD)) {
|
|
143
|
+
const [header = '', ...names] = record.split('\n');
|
|
144
|
+
const [commit, date, subject] = header.split(FIELD);
|
|
145
|
+
if (commit === undefined || date === undefined || subject === undefined || commit.trim() === '') {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
current = names.map((name) => name.trim()).find((name) => name !== '') ?? current;
|
|
149
|
+
commits.push({ commit: commit.trim(), date, subject, path: current });
|
|
150
|
+
}
|
|
151
|
+
return commits;
|
|
152
|
+
}
|
|
153
|
+
function snapshot(content) {
|
|
154
|
+
const entries = parseBaseline(content);
|
|
155
|
+
if (isUnreadableBaseline(content, entries)) {
|
|
156
|
+
return { count: null, entries: [] };
|
|
157
|
+
}
|
|
158
|
+
return { count: { entries: entries.length, errors: entries.reduce((sum, entry) => sum + entry.count, 0) }, entries };
|
|
159
|
+
}
|
|
160
|
+
function row(commit, date, subject, file, now, before) {
|
|
161
|
+
const leesbaar = now.count !== null && before.count !== null;
|
|
162
|
+
return {
|
|
163
|
+
commit,
|
|
164
|
+
date,
|
|
165
|
+
subject,
|
|
166
|
+
file,
|
|
167
|
+
count: now.count,
|
|
168
|
+
delta: now.count === null || before.count === null ? null : { entries: now.count.entries - before.count.entries, errors: now.count.errors - before.count.errors },
|
|
169
|
+
changes: leesbaar ? changesBetween(before.entries, now.entries) : [],
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/** Per identifier het verschil in genegeerde fouten; de grootste eerst, bij gelijk verschil alfabetisch. */
|
|
173
|
+
function changesBetween(before, now) {
|
|
174
|
+
const change = new Map();
|
|
175
|
+
for (const entry of before) {
|
|
176
|
+
change.set(entry.identifier, (change.get(entry.identifier) ?? 0) - entry.count);
|
|
177
|
+
}
|
|
178
|
+
for (const entry of now) {
|
|
179
|
+
change.set(entry.identifier, (change.get(entry.identifier) ?? 0) + entry.count);
|
|
180
|
+
}
|
|
181
|
+
return [...change]
|
|
182
|
+
.filter(([, verschil]) => verschil !== 0)
|
|
183
|
+
.sort((a, b) => Math.abs(b[1]) - Math.abs(a[1]) || a[0].localeCompare(b[0]))
|
|
184
|
+
.slice(0, CHANGE_ROWS)
|
|
185
|
+
.map(([identifier, verschil]) => ({ identifier, change: verschil }));
|
|
186
|
+
}
|
|
187
|
+
function sameEntries(a, b) {
|
|
188
|
+
return a.count !== null && b.count !== null && JSON.stringify(a.entries) === JSON.stringify(b.entries);
|
|
189
|
+
}
|
|
190
|
+
/** Het pad in een commit, relatief aan het project als het daarbinnen lag. */
|
|
191
|
+
function display(path, prefix) {
|
|
192
|
+
return prefix !== '' && path.startsWith(prefix) ? path.slice(prefix.length) : path;
|
|
193
|
+
}
|
|
194
|
+
function readOrEmpty(file) {
|
|
195
|
+
try {
|
|
196
|
+
return readFileSync(file, 'utf8');
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return '';
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function noBaselineNotice(project) {
|
|
203
|
+
if (project.config === null) {
|
|
204
|
+
return `${project.path} has no phpstan.neon(.dist), so no baseline is included.`;
|
|
205
|
+
}
|
|
206
|
+
const los = findBaselineFiles(project);
|
|
207
|
+
return los.length > 0
|
|
208
|
+
? `${los.join(', ')} ${los.length === 1 ? 'is' : 'are'} not included by the config, so ${los.length === 1 ? 'it hides' : 'they hide'} nothing; no history is shown.`
|
|
209
|
+
: 'The config includes no phpstan-baseline*.neon from the project root, so there is no baseline history.';
|
|
210
|
+
}
|
|
211
|
+
/** Schrijft het verloop uit als tekst voor het model. */
|
|
212
|
+
export function renderHistory(report) {
|
|
213
|
+
const lines = [];
|
|
214
|
+
if (report.notices.length > 0) {
|
|
215
|
+
lines.push(...report.notices.map((notice) => `Note: ${notice}`), '');
|
|
216
|
+
}
|
|
217
|
+
if (report.files.length === 0) {
|
|
218
|
+
lines.push('No baseline history.');
|
|
219
|
+
return lines.join('\n');
|
|
220
|
+
}
|
|
221
|
+
for (const history of report.files) {
|
|
222
|
+
lines.push(...renderFile(history), '');
|
|
223
|
+
}
|
|
224
|
+
lines.push('Each change is compared with the one below it, along the first-parent line of HEAD: a merged branch counts as ' +
|
|
225
|
+
'one change. Counts are ignored errors; a baseline entry can cover several.');
|
|
226
|
+
return lines.join('\n');
|
|
227
|
+
}
|
|
228
|
+
function renderFile(history) {
|
|
229
|
+
const committed = history.rows.filter((row) => row.commit !== null);
|
|
230
|
+
const newest = history.rows[0];
|
|
231
|
+
const lines = [headline(history, committed.length, newest?.count ?? null), ''];
|
|
232
|
+
for (const row of history.rows) {
|
|
233
|
+
const date = row.date === null ? 'working copy' : row.date.slice(0, 10);
|
|
234
|
+
const commit = row.commit === null ? '(not committed)' : row.commit.slice(0, 10);
|
|
235
|
+
const count = row.count === null ? '?' : String(row.count.errors);
|
|
236
|
+
const delta = row.delta === null ? '?' : signed(row.delta.errors);
|
|
237
|
+
const kolommen = ` ${date.padEnd(12)} ${commit.padEnd(15)} ${count.padStart(6)} ${delta.padStart(6)} `;
|
|
238
|
+
// De regels eronder beginnen onder het onderwerp.
|
|
239
|
+
const inspring = ' '.repeat(kolommen.length);
|
|
240
|
+
lines.push(`${kolommen}${row.subject ?? ''}`.trimEnd());
|
|
241
|
+
if (row.changes.length > 0) {
|
|
242
|
+
lines.push(`${inspring}${row.changes.map((change) => `${signed(change.change)} ${change.identifier}`).join(', ')}`);
|
|
243
|
+
}
|
|
244
|
+
if (row.file !== history.file) {
|
|
245
|
+
lines.push(`${inspring}(then named ${row.file})`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (history.olderCommits) {
|
|
249
|
+
lines.push('', `Older commits changed ${history.file} too; pass a higher limit (up to ${String(MAX_HISTORY_LIMIT)}) to see them.`);
|
|
250
|
+
}
|
|
251
|
+
return lines;
|
|
252
|
+
}
|
|
253
|
+
function headline(history, committed, now) {
|
|
254
|
+
const nu = now === null ? 'cannot be read now' : `ignores ${String(now.errors)} error(s) in ${String(now.entries)} ${now.entries === 1 ? 'entry' : 'entries'} now`;
|
|
255
|
+
if (committed === 0) {
|
|
256
|
+
return `${history.file} ${nu}. It has never been committed, so there is no history yet.`;
|
|
257
|
+
}
|
|
258
|
+
if (committed === 1 && !history.olderCommits && history.rows.length === 1) {
|
|
259
|
+
return `${history.file} ${nu}. Only one commit touched it, the one that created it; there is nothing to compare yet.`;
|
|
260
|
+
}
|
|
261
|
+
const start = history.start;
|
|
262
|
+
const end = now;
|
|
263
|
+
const verloop = start === null || end === null
|
|
264
|
+
? 'the net change is unknown because a version cannot be read'
|
|
265
|
+
: `${String(start.errors)} → ${String(end.errors)} ignored error(s) (net ${signed(end.errors - start.errors)})`;
|
|
266
|
+
const deltas = history.rows.flatMap((row) => (row.delta === null ? [] : [row.delta.errors]));
|
|
267
|
+
const erbij = deltas.filter((delta) => delta > 0).length;
|
|
268
|
+
const eraf = deltas.filter((delta) => delta < 0).length;
|
|
269
|
+
return (`${history.file} ${nu}. Over the last ${String(history.rows.length)} change(s): ${verloop}; ` +
|
|
270
|
+
`${String(erbij)} of them added errors, ${String(eraf)} removed some.`);
|
|
271
|
+
}
|
|
272
|
+
function signed(value) {
|
|
273
|
+
return value > 0 ? `+${String(value)}` : String(value);
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,16 @@ export interface Execution {
|
|
|
9
9
|
readonly stderr: string;
|
|
10
10
|
readonly spawnError: NodeJS.ErrnoException | null;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Of deze server de run gestopt heeft, door een timeout of een annulering.
|
|
14
|
+
*
|
|
15
|
+
* Op POSIX blijkt dat uit het signaal. Op Windows niet: `taskkill /F` laat het proces eindigen
|
|
16
|
+
* met exit code 1 en zonder signaal, en tot hier las elke timeout en elke annulering daar als
|
|
17
|
+
* "PHPStan returned no usable JSON", met het advies de cache te legen. Nagemeten toen de
|
|
18
|
+
* testsuite op Windows ging draaien. Daarom telt ook de reden, maar alleen als het proces niet
|
|
19
|
+
* toch nog zelf klaar was (`completed`): een run die net op tijd eindigde, is geen timeout.
|
|
20
|
+
*/
|
|
21
|
+
export declare function wasStopped(execution: Pick<Execution, 'signal' | 'reason'>, completed: boolean): boolean;
|
|
12
22
|
/**
|
|
13
23
|
* Start PHPStan zonder shell. Bewust spawn en niet execFile: die laatste kapt de
|
|
14
24
|
* output af op maxBuffer (1 MB), en de JSON van een groot project gaat daar
|