phpstan-mcp-mx 0.17.0 → 0.19.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 +17 -4
- package/README.md +85 -50
- package/dist/baseline.js +15 -11
- package/dist/baseline.js.map +1 -1
- package/dist/changed.js +11 -11
- package/dist/changed.js.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/defaults.js +11 -11
- package/dist/defaults.js.map +1 -1
- package/dist/dumptype.d.ts +86 -0
- package/dist/dumptype.js +190 -0
- package/dist/dumptype.js.map +1 -0
- package/dist/failure.d.ts +1 -1
- package/dist/failure.js.map +1 -1
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/phpstan/output.js +2 -2
- package/dist/phpstan/output.js.map +1 -1
- package/dist/phpstan/parameters.js +10 -10
- package/dist/phpstan/parameters.js.map +1 -1
- package/dist/phpstan/process.js +2 -2
- package/dist/phpstan/process.js.map +1 -1
- package/dist/phpstan/queue.js +3 -3
- package/dist/phpstan/queue.js.map +1 -1
- package/dist/phpstan.d.ts +29 -2
- package/dist/phpstan.js +130 -45
- package/dist/phpstan.js.map +1 -1
- package/dist/project.js +12 -12
- package/dist/project.js.map +1 -1
- package/dist/report.js +31 -31
- package/dist/report.js.map +1 -1
- package/dist/roots.js +3 -3
- package/dist/roots.js.map +1 -1
- package/dist/runner.js +10 -10
- package/dist/runner.js.map +1 -1
- package/dist/server.js +3 -3
- package/dist/server.js.map +1 -1
- package/dist/tmpdir.js +4 -4
- package/dist/tmpdir.js.map +1 -1
- package/dist/tools/analysis.js +38 -38
- package/dist/tools/analysis.js.map +1 -1
- package/dist/tools/inspect.d.ts +2 -0
- package/dist/tools/inspect.js +161 -85
- package/dist/tools/inspect.js.map +1 -1
- package/dist/tools/prompts.js +165 -162
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/shared.js +38 -38
- package/dist/tools/shared.js.map +1 -1
- package/dist/tools/writes.js +23 -23
- package/dist/tools/writes.js.map +1 -1
- package/dist/tools.js +2 -1
- package/dist/tools.js.map +1 -1
- package/dist/unmatched.js +31 -30
- package/dist/unmatched.js.map +1 -1
- package/dist/version.d.ts +17 -4
- package/dist/version.js +27 -4
- package/dist/version.js.map +1 -1
- package/package.json +1 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysis.js","sourceRoot":"","sources":["../../src/tools/analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,OAAO,EACL,aAAa,EACb,MAAM,EACN,cAAc,EACd,eAAe,EACf,QAAQ,EACR,WAAW,EACX,MAAM,EACN,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,sFAAsF;AACtF,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,KAAa,EAAE,IAAc;IACrF,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"analysis.js","sourceRoot":"","sources":["../../src/tools/analysis.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/inspect.d.ts
CHANGED
|
@@ -14,3 +14,5 @@ export declare function registerDiagnose(server: McpServer, roots: Root[]): void
|
|
|
14
14
|
export declare function registerBaselineSummary(server: McpServer, roots: Root[]): void;
|
|
15
15
|
/** Hangt `unmatched_ignores` aan de server: negeerregels die niets meer doen. */
|
|
16
16
|
export declare function registerUnmatchedIgnores(server: McpServer, roots: Root[]): void;
|
|
17
|
+
/** Hangt `inspect_type` aan de server: het type dat PHPStan op een regel afleidt. */
|
|
18
|
+
export declare function registerInspectType(server: McpServer, roots: Root[]): void;
|
package/dist/tools/inspect.js
CHANGED
|
@@ -8,17 +8,18 @@ import { loadRunners } from '../runner.js';
|
|
|
8
8
|
import { DEFAULT_LIMIT, MAX_LIMIT } from '../report.js';
|
|
9
9
|
import { loadTmpDirMode } from '../tmpdir.js';
|
|
10
10
|
import { findUnmatchedIgnores, renderUnmatched } from '../unmatched.js';
|
|
11
|
+
import { MAX_EXPRESSIONS, inspectType, renderTypes } from '../dumptype.js';
|
|
11
12
|
import { renderParameters } from '../phpstan/parameters.js';
|
|
12
13
|
import { VERSION } from '../version.js';
|
|
13
|
-
import { failure, log, nullable, projectArgument, readOnly, toFailure } from './shared.js';
|
|
14
|
+
import { common, configArgument, failure, log, nullable, projectArgument, readOnly, toFailure } from './shared.js';
|
|
14
15
|
import { writesAllowed } from './writes.js';
|
|
15
16
|
/** Hangt `list_projects` aan de server: welke projecten binnen bereik liggen. */
|
|
16
17
|
export function registerListProjects(server, roots) {
|
|
17
18
|
server.registerTool('list_projects', {
|
|
18
|
-
title: 'PHP
|
|
19
|
-
description: '
|
|
20
|
-
'PHPStan
|
|
21
|
-
'
|
|
19
|
+
title: 'List PHP projects',
|
|
20
|
+
description: 'Lists the PHP projects this server may analyse, with for each project whether ' +
|
|
21
|
+
'PHPStan is installed and which config file is present. Use the `path` from the ' +
|
|
22
|
+
'result as the `project` argument for the other tools.',
|
|
22
23
|
inputSchema: {},
|
|
23
24
|
outputSchema: {
|
|
24
25
|
projects: z.array(z.object({
|
|
@@ -26,13 +27,13 @@ export function registerListProjects(server, roots) {
|
|
|
26
27
|
root: z.string(),
|
|
27
28
|
hasPhpstan: z.boolean(),
|
|
28
29
|
config: nullable(z.string()),
|
|
29
|
-
hasGit: z.boolean().describe('
|
|
30
|
-
runner: nullable(z.string()).describe('
|
|
30
|
+
hasGit: z.boolean().describe('Whether analyse_changed can be used here'),
|
|
31
|
+
runner: nullable(z.string()).describe('Command PHPStan runs through here, or null for the host'),
|
|
31
32
|
defaults: nullable(z.object({
|
|
32
33
|
memoryLimit: nullable(z.string()),
|
|
33
34
|
timeoutSeconds: nullable(z.number()),
|
|
34
35
|
config: nullable(z.string()),
|
|
35
|
-
})).describe('
|
|
36
|
+
})).describe('Defaults the server sets for this project; a tool argument takes precedence'),
|
|
36
37
|
})),
|
|
37
38
|
problems: z.array(z.object({ root: z.string(), problem: z.string() })),
|
|
38
39
|
},
|
|
@@ -42,9 +43,9 @@ export function registerListProjects(server, roots) {
|
|
|
42
43
|
// PHPStan hier niet eens gestart is. Juist bij deze tool — het beginpunt — moet
|
|
43
44
|
// een aanroeper kunnen zien dat het aan de serverconfiguratie ligt.
|
|
44
45
|
if (roots.length === 0) {
|
|
45
|
-
return failure(`
|
|
46
|
-
'MCP
|
|
47
|
-
'
|
|
46
|
+
return failure(`No project directories are configured. Set ${ROOTS_ENV_VAR} in the ` +
|
|
47
|
+
'MCP server configuration to the absolute paths that may be analysed, ' +
|
|
48
|
+
'separated by colons.', 'no_roots_configured', { hint: `Set ${ROOTS_ENV_VAR}, or "roots" in the config file.` });
|
|
48
49
|
}
|
|
49
50
|
const projects = discoverProjects(roots);
|
|
50
51
|
const problems = roots
|
|
@@ -67,31 +68,31 @@ export function registerListProjects(server, roots) {
|
|
|
67
68
|
function renderProjects(projects, problems) {
|
|
68
69
|
const lines = [];
|
|
69
70
|
if (projects.length === 0) {
|
|
70
|
-
lines.push('
|
|
71
|
+
lines.push('No PHP projects found under the configured directories.');
|
|
71
72
|
}
|
|
72
73
|
else {
|
|
73
|
-
lines.push(`${projects.length} project(
|
|
74
|
+
lines.push(`${projects.length} project(s):`);
|
|
74
75
|
for (const project of projects) {
|
|
75
|
-
const config = project.config ?? '
|
|
76
|
-
const phpstan = project.hasPhpstan ? 'phpstan
|
|
77
|
-
const git = project.hasGit ? 'git' : '
|
|
76
|
+
const config = project.config ?? 'no config';
|
|
77
|
+
const phpstan = project.hasPhpstan ? 'phpstan present' : 'phpstan NOT installed';
|
|
78
|
+
const git = project.hasGit ? 'git' : 'no git';
|
|
78
79
|
const waar = project.runner === null ? '' : `, via ${project.runner}`;
|
|
79
|
-
const standaard = project.defaults === null ? '' : `,
|
|
80
|
+
const standaard = project.defaults === null ? '' : `, defaults ${describeDefaults(project.defaults)}`;
|
|
80
81
|
lines.push(`- ${project.path} (${phpstan}, ${config}, ${git}${waar}${standaard})`);
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
if (problems.length > 0) {
|
|
84
|
-
lines.push('', '
|
|
85
|
+
lines.push('', 'Skipped entries from the configuration:');
|
|
85
86
|
for (const problem of problems)
|
|
86
87
|
lines.push(`- ${problem.root}: ${problem.problem}`);
|
|
87
88
|
}
|
|
88
89
|
return lines.join('\n');
|
|
89
90
|
}
|
|
90
|
-
/** "
|
|
91
|
+
/** "memory 2G, timeout 600s" — alleen wat gezet is, in een vaste volgorde. */
|
|
91
92
|
function describeDefaults(defaults) {
|
|
92
93
|
const delen = [];
|
|
93
94
|
if (defaults.memoryLimit !== null)
|
|
94
|
-
delen.push(`
|
|
95
|
+
delen.push(`memory ${defaults.memoryLimit}`);
|
|
95
96
|
if (defaults.timeoutSeconds !== null)
|
|
96
97
|
delen.push(`timeout ${String(defaults.timeoutSeconds)}s`);
|
|
97
98
|
if (defaults.config !== null)
|
|
@@ -105,24 +106,24 @@ function describeDefaults(defaults) {
|
|
|
105
106
|
*/
|
|
106
107
|
export function registerServerConfig(server, roots) {
|
|
107
108
|
server.registerTool('server_config', {
|
|
108
|
-
title: '
|
|
109
|
-
description: '
|
|
110
|
-
'
|
|
111
|
-
'
|
|
112
|
-
'
|
|
109
|
+
title: 'Server settings',
|
|
110
|
+
description: 'Returns the settings this server runs with: which project directories are in ' +
|
|
111
|
+
'scope, the default memory limit, how many analyses may run in parallel, where ' +
|
|
112
|
+
'temporary files go and whether writing tools are enabled. Use this when something ' +
|
|
113
|
+
'is refused or slower than expected, before you doubt the project.',
|
|
113
114
|
inputSchema: {},
|
|
114
115
|
outputSchema: {
|
|
115
116
|
version: z.string(),
|
|
116
117
|
roots: z.array(z.object({
|
|
117
|
-
raw: z.string().describe('
|
|
118
|
-
path: nullable(z.string()).describe('
|
|
118
|
+
raw: z.string().describe('As given in the environment variable'),
|
|
119
|
+
path: nullable(z.string()).describe('The resolved path, or null if the root is unusable'),
|
|
119
120
|
problem: nullable(z.string()),
|
|
120
121
|
})),
|
|
121
|
-
memoryLimit: nullable(z.string()).describe('
|
|
122
|
-
maxParallel: nullable(z.number()).describe('
|
|
122
|
+
memoryLimit: nullable(z.string()).describe('Default --memory-limit, or null if it is not set'),
|
|
123
|
+
maxParallel: nullable(z.number()).describe('How many analyses may run in parallel; null if the value was rejected'),
|
|
123
124
|
tmpDir: nullable(z.string()).describe('"project" of "shared"'),
|
|
124
|
-
writesAllowed: z.boolean().describe('
|
|
125
|
-
runners: z.array(z.string()).describe('
|
|
125
|
+
writesAllowed: z.boolean().describe('Whether generate_baseline is registered'),
|
|
126
|
+
runners: z.array(z.string()).describe('Projects with a runner (execution environment)'),
|
|
126
127
|
projectDefaults: z
|
|
127
128
|
.array(z.object({
|
|
128
129
|
project: z.string(),
|
|
@@ -130,10 +131,10 @@ export function registerServerConfig(server, roots) {
|
|
|
130
131
|
timeoutSeconds: nullable(z.number()),
|
|
131
132
|
config: nullable(z.string()),
|
|
132
133
|
}))
|
|
133
|
-
.describe('
|
|
134
|
+
.describe('Projects with per-project defaults; a tool argument still takes precedence'),
|
|
134
135
|
problems: z
|
|
135
136
|
.array(z.string())
|
|
136
|
-
.describe('
|
|
137
|
+
.describe('Settings that were rejected; those fields are then null'),
|
|
137
138
|
},
|
|
138
139
|
annotations: readOnly(),
|
|
139
140
|
}, () => {
|
|
@@ -178,23 +179,23 @@ function setting(read, problems) {
|
|
|
178
179
|
}
|
|
179
180
|
}
|
|
180
181
|
function renderConfig(config) {
|
|
181
|
-
const lines = [`phpstan-mcp ${config.version}`, '', '
|
|
182
|
+
const lines = [`phpstan-mcp ${config.version}`, '', 'Project directories:'];
|
|
182
183
|
if (config.roots.length === 0) {
|
|
183
|
-
lines.push(` (
|
|
184
|
+
lines.push(` (none; set ${ROOTS_ENV_VAR})`);
|
|
184
185
|
}
|
|
185
186
|
else {
|
|
186
187
|
for (const root of config.roots) {
|
|
187
188
|
lines.push(` ${root.path ?? root.raw}${root.problem === null ? '' : ` — ${root.problem}`}`);
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
|
-
lines.push('', `
|
|
191
|
+
lines.push('', `Memory limit: ${config.memoryLimit ?? "not set (PHP's own limit applies)"}`, `Parallel: ${config.maxParallel === null ? 'unknown' : String(config.maxParallel)}`, `Temp directory: ${config.tmpDir === null ? 'unknown' : config.tmpDir}`, `Writing tools: ${config.writesAllowed ? 'on (generate_baseline exists)' : 'off'}`, `Runners: ${config.runners.length === 0 ? 'none' : config.runners.join(', ')}`);
|
|
191
192
|
if (config.projectDefaults.length > 0) {
|
|
192
|
-
lines.push('', '
|
|
193
|
+
lines.push('', 'Per-project defaults (a tool argument takes precedence):');
|
|
193
194
|
for (const entry of config.projectDefaults)
|
|
194
195
|
lines.push(` ${entry.project}: ${describeDefaults(entry)}`);
|
|
195
196
|
}
|
|
196
197
|
if (config.problems.length > 0) {
|
|
197
|
-
lines.push('', '
|
|
198
|
+
lines.push('', 'Rejected settings:');
|
|
198
199
|
for (const problem of config.problems)
|
|
199
200
|
lines.push(`- ${problem}`);
|
|
200
201
|
}
|
|
@@ -203,50 +204,50 @@ function renderConfig(config) {
|
|
|
203
204
|
/** Hangt `diagnose_project` aan de server: PHPStans eigen opstelling in een project. */
|
|
204
205
|
export function registerDiagnose(server, roots) {
|
|
205
206
|
server.registerTool('diagnose_project', {
|
|
206
|
-
title: 'PHPStan
|
|
207
|
-
description: '
|
|
208
|
-
'configs
|
|
209
|
-
'
|
|
210
|
-
'(
|
|
211
|
-
'
|
|
212
|
-
'
|
|
207
|
+
title: 'Inspect PHPStan setup',
|
|
208
|
+
description: 'Asks PHPStan itself for its setup in this project: PHP and PHPStan version, the ' +
|
|
209
|
+
'configs that Composer packages bring along (such as Larastan) and whether the turbo ' +
|
|
210
|
+
'extension is enabled — plus the configuration as PHPStan ends up using it: the level ' +
|
|
211
|
+
'(also when it is set in a config from vendor/), the paths, the number of ignore rules ' +
|
|
212
|
+
'and the temp directory. Does not run an analysis. Use this when a project behaves ' +
|
|
213
|
+
'differently from another project, before you start doubting the code.',
|
|
213
214
|
inputSchema: {
|
|
214
215
|
project: projectArgument,
|
|
215
216
|
timeoutSeconds: z.number().int().positive().max(1800).optional(),
|
|
216
217
|
},
|
|
217
218
|
outputSchema: {
|
|
218
219
|
project: z.string(),
|
|
219
|
-
output: z.string().describe('
|
|
220
|
+
output: z.string().describe("PHPStan's own text, unchanged"),
|
|
220
221
|
parameters: nullable(z.object({
|
|
221
222
|
level: nullable(z.union([z.number(), z.string()])),
|
|
222
223
|
paths: z.array(z.string()),
|
|
223
224
|
excludePaths: z.array(z.string()),
|
|
224
|
-
ignoreErrors: z.number().describe('
|
|
225
|
+
ignoreErrors: z.number().describe('Ignore rules in total: the baseline plus ignoreErrors from every config'),
|
|
225
226
|
reportUnmatchedIgnoredErrors: nullable(z.boolean()),
|
|
226
|
-
tmpDir: nullable(z.string()).describe('
|
|
227
|
+
tmpDir: nullable(z.string()).describe('Where PHPStan puts its cache: what clear_result_cache clears'),
|
|
227
228
|
bootstrapFiles: z.array(z.string()),
|
|
228
|
-
})).describe('
|
|
229
|
-
parametersProblem: nullable(z.string()).describe('
|
|
229
|
+
})).describe('The configuration as PHPStan ends up using it, including what comes from vendor/'),
|
|
230
|
+
parametersProblem: nullable(z.string()).describe('Why parameters is missing, e.g. a bootstrap that fails to start'),
|
|
230
231
|
},
|
|
231
232
|
annotations: readOnly(),
|
|
232
233
|
}, async (args, extra) => {
|
|
233
234
|
const begin = Date.now();
|
|
234
235
|
try {
|
|
235
236
|
const resolved = resolveProject(args.project, roots);
|
|
236
|
-
log(server, 'debug', {
|
|
237
|
+
log(server, 'debug', { event: 'diagnosis started', project: resolved.path });
|
|
237
238
|
const diagnosis = await diagnose(resolved, {
|
|
238
239
|
...(args.timeoutSeconds === undefined ? {} : { timeoutMs: args.timeoutSeconds * 1000 }),
|
|
239
240
|
signal: extra.signal,
|
|
240
241
|
});
|
|
241
242
|
log(server, 'info', {
|
|
242
|
-
|
|
243
|
+
event: 'diagnosis finished',
|
|
243
244
|
project: resolved.path,
|
|
244
|
-
|
|
245
|
+
durationMs: Date.now() - begin,
|
|
245
246
|
});
|
|
246
247
|
// PHPStans eigen tekst eerst en ongewijzigd; de samenvatting eronder, zodat
|
|
247
248
|
// duidelijk blijft wat van PHPStan komt en wat deze server erbij zet.
|
|
248
249
|
const aanvulling = diagnosis.parameters === null
|
|
249
|
-
? `
|
|
250
|
+
? `Effective configuration: not available. ${diagnosis.parametersProblem ?? ''}`.trim()
|
|
250
251
|
: renderParameters(diagnosis.parameters);
|
|
251
252
|
return {
|
|
252
253
|
content: [{ type: 'text', text: `${diagnosis.output}\n\n${aanvulling}` }],
|
|
@@ -261,27 +262,27 @@ export function registerDiagnose(server, roots) {
|
|
|
261
262
|
/** Hangt `baseline_summary` aan de server: wat de baseline verbergt. */
|
|
262
263
|
export function registerBaselineSummary(server, roots) {
|
|
263
264
|
server.registerTool('baseline_summary', {
|
|
264
|
-
title: '
|
|
265
|
-
description: '
|
|
266
|
-
'
|
|
267
|
-
'
|
|
268
|
-
'
|
|
269
|
-
'
|
|
265
|
+
title: 'Summarise baseline',
|
|
266
|
+
description: 'Reads the phpstan-baseline*.neon of a project and counts what is ignored, per ' +
|
|
267
|
+
'identifier and per file. Does not run an analysis. Note: what is in here is exactly ' +
|
|
268
|
+
'what analyse_project does NOT report — a project that includes its baseline only ' +
|
|
269
|
+
'reports the errors that are new. With `path`, also the entries for one file, with ' +
|
|
270
|
+
'identifier, count and pattern.',
|
|
270
271
|
inputSchema: {
|
|
271
272
|
project: projectArgument,
|
|
272
273
|
path: z
|
|
273
274
|
.string()
|
|
274
275
|
.optional()
|
|
275
|
-
.describe('
|
|
276
|
+
.describe('One file, relative to the project root: also return the baseline entries for just that file'),
|
|
276
277
|
},
|
|
277
278
|
outputSchema: {
|
|
278
279
|
project: z.string(),
|
|
279
|
-
hasBaseline: z.boolean().describe('False
|
|
280
|
+
hasBaseline: z.boolean().describe('False means: no baseline, so nothing is ignored'),
|
|
280
281
|
files: z.array(z.object({ file: z.string(), entries: z.number(), errors: z.number() })),
|
|
281
282
|
totals: z.object({ entries: z.number(), errors: z.number() }),
|
|
282
283
|
byIdentifier: z.array(z.object({ identifier: z.string(), count: z.number() })),
|
|
283
284
|
byPath: z.array(z.object({ path: z.string(), count: z.number() })),
|
|
284
|
-
entries: nullable(z.array(z.object({ file: z.string(), identifier: z.string(), count: z.number(), message: nullable(z.string()) }))).describe('
|
|
285
|
+
entries: nullable(z.array(z.object({ file: z.string(), identifier: z.string(), count: z.number(), message: nullable(z.string()) }))).describe('The entries for `path`; null if no path was given'),
|
|
285
286
|
},
|
|
286
287
|
annotations: readOnly(),
|
|
287
288
|
}, ({ project, path }) => {
|
|
@@ -309,41 +310,42 @@ const MAX_PATTERN_CHARS = 200;
|
|
|
309
310
|
/** De baseline-regels voor één bestand, als tekst. */
|
|
310
311
|
function renderEntries(path, entries) {
|
|
311
312
|
if (entries.length === 0)
|
|
312
|
-
return `
|
|
313
|
+
return `No baseline entries for ${path}.`;
|
|
313
314
|
const kort = (message) => message === null ? '' : message.length <= MAX_PATTERN_CHARS ? ` ${message}` : ` ${message.slice(0, MAX_PATTERN_CHARS)}…`;
|
|
314
315
|
return [
|
|
315
|
-
`${String(entries.length)} baseline
|
|
316
|
+
`${String(entries.length)} baseline entr${entries.length === 1 ? 'y' : 'ies'} for ${path}:`,
|
|
316
317
|
...entries.map((entry) => ` ${String(entry.count).padStart(3)} ${entry.identifier}${kort(entry.message)}`),
|
|
317
318
|
].join('\n');
|
|
318
319
|
}
|
|
319
320
|
/** Hangt `unmatched_ignores` aan de server: negeerregels die niets meer doen. */
|
|
320
321
|
export function registerUnmatchedIgnores(server, roots) {
|
|
321
322
|
server.registerTool('unmatched_ignores', {
|
|
322
|
-
title: '
|
|
323
|
-
description: '
|
|
324
|
-
'
|
|
325
|
-
'baseline
|
|
326
|
-
'
|
|
327
|
-
'
|
|
323
|
+
title: 'Find stale ignore rules',
|
|
324
|
+
description: 'Runs a full analysis with reportUnmatchedIgnoredErrors enabled and returns the ' +
|
|
325
|
+
'ignore rules that no longer match anything, or match less often than their count — ' +
|
|
326
|
+
'from the baseline and from ignoreErrors in the config. Such a rule belongs to an ' +
|
|
327
|
+
'error that has been fixed and can be removed. Does not change anything in the ' +
|
|
328
|
+
'project: the temporary config lives outside it — for a project with a runner, in ' +
|
|
329
|
+
"that runner's temp directory.",
|
|
328
330
|
inputSchema: {
|
|
329
331
|
project: projectArgument,
|
|
330
332
|
memoryLimit: z
|
|
331
333
|
.string()
|
|
332
334
|
.optional()
|
|
333
|
-
.describe('
|
|
335
|
+
.describe('E.g. "1G"; this is a full analysis, so it may need more'),
|
|
334
336
|
timeoutSeconds: z.number().int().positive().max(1800).optional(),
|
|
335
|
-
offset: z.number().int().min(0).optional().describe('
|
|
337
|
+
offset: z.number().int().min(0).optional().describe('Skip the first N entries'),
|
|
336
338
|
limit: z
|
|
337
339
|
.number()
|
|
338
340
|
.int()
|
|
339
341
|
.min(1)
|
|
340
342
|
.max(MAX_LIMIT)
|
|
341
343
|
.optional()
|
|
342
|
-
.describe(`
|
|
344
|
+
.describe(`How many entries this response contains (default ${String(DEFAULT_LIMIT)})`),
|
|
343
345
|
},
|
|
344
346
|
outputSchema: {
|
|
345
347
|
project: z.string(),
|
|
346
|
-
baselineFiles: z.array(z.string()).describe('
|
|
348
|
+
baselineFiles: z.array(z.string()).describe('The baseline files the config includes'),
|
|
347
349
|
totals: z.object({
|
|
348
350
|
unmatched: z.number(),
|
|
349
351
|
countTooHigh: z.number(),
|
|
@@ -351,25 +353,25 @@ export function registerUnmatchedIgnores(server, roots) {
|
|
|
351
353
|
general: z.number(),
|
|
352
354
|
otherFindings: z
|
|
353
355
|
.number()
|
|
354
|
-
.describe('
|
|
356
|
+
.describe('Regular findings from the same run; a new baseline would hide those too'),
|
|
355
357
|
}),
|
|
356
358
|
byPath: z.array(z.object({ path: z.string(), count: z.number() })),
|
|
357
359
|
entries: z.array(z.object({
|
|
358
|
-
path: z.string().describe('
|
|
360
|
+
path: z.string().describe('Path relative to the project root'),
|
|
359
361
|
identifier: nullable(z.string()),
|
|
360
362
|
pattern: z.string(),
|
|
361
363
|
kind: z.enum(['unmatched', 'countTooHigh']),
|
|
362
364
|
expected: nullable(z.number()),
|
|
363
365
|
occurred: nullable(z.number()),
|
|
364
|
-
inBaseline: nullable(z.boolean()).describe('
|
|
366
|
+
inBaseline: nullable(z.boolean()).describe('Whether the rule comes from an included baseline; null if that could not be read'),
|
|
365
367
|
})),
|
|
366
368
|
general: z
|
|
367
369
|
.array(z.string())
|
|
368
|
-
.describe('
|
|
370
|
+
.describe('Patterns without a path that no longer match anything; these are not in the baseline'),
|
|
369
371
|
generalErrors: z.array(z.string()),
|
|
370
372
|
warnings: z
|
|
371
373
|
.array(z.string())
|
|
372
|
-
.describe('
|
|
374
|
+
.describe('If this contains "Result is incomplete", PHPStan may have missed stale rules'),
|
|
373
375
|
notices: z.array(z.string()),
|
|
374
376
|
omitted: z.object({ general: z.number(), generalErrors: z.number(), warnings: z.number() }),
|
|
375
377
|
page: z.object({
|
|
@@ -385,18 +387,18 @@ export function registerUnmatchedIgnores(server, roots) {
|
|
|
385
387
|
const begin = Date.now();
|
|
386
388
|
try {
|
|
387
389
|
const resolved = resolveProject(args.project, roots);
|
|
388
|
-
log(server, 'debug', {
|
|
390
|
+
log(server, 'debug', { event: 'checking ignore rules', project: resolved.path });
|
|
389
391
|
const report = await findUnmatchedIgnores(resolved, {
|
|
390
392
|
...(args.memoryLimit === undefined ? {} : { memoryLimit: args.memoryLimit }),
|
|
391
393
|
...(args.timeoutSeconds === undefined ? {} : { timeoutMs: args.timeoutSeconds * 1000 }),
|
|
392
394
|
signal: extra.signal,
|
|
393
395
|
}, { offset: args.offset, limit: args.limit });
|
|
394
396
|
log(server, 'info', {
|
|
395
|
-
|
|
397
|
+
event: 'ignore rules checked',
|
|
396
398
|
project: resolved.path,
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
399
|
+
stale: report.totals.unmatched + report.totals.countTooHigh,
|
|
400
|
+
general: report.totals.general,
|
|
401
|
+
durationMs: Date.now() - begin,
|
|
400
402
|
});
|
|
401
403
|
return {
|
|
402
404
|
content: [{ type: 'text', text: renderUnmatched(report) }],
|
|
@@ -408,4 +410,78 @@ export function registerUnmatchedIgnores(server, roots) {
|
|
|
408
410
|
}
|
|
409
411
|
});
|
|
410
412
|
}
|
|
413
|
+
/** Hangt `inspect_type` aan de server: het type dat PHPStan op een regel afleidt. */
|
|
414
|
+
export function registerInspectType(server, roots) {
|
|
415
|
+
server.registerTool('inspect_type', {
|
|
416
|
+
title: 'Inspect inferred type',
|
|
417
|
+
description: 'Shows the type PHPStan infers for one or more PHP expressions right before a given ' +
|
|
418
|
+
'line, without changing the project: the server inserts `\\PHPStan\\dumpType(...)` ' +
|
|
419
|
+
'before `line` in a temporary copy of the file and has PHPStan read that copy in place ' +
|
|
420
|
+
"of the original (PHPStan's editor mode). `line` must be the first line of a statement " +
|
|
421
|
+
'inside a function or method; anywhere else the answer is a parse error that says so. ' +
|
|
422
|
+
'Use this instead of guessing a type, and before reaching for a cast, `assert()` or an ' +
|
|
423
|
+
'inline `@var`.',
|
|
424
|
+
inputSchema: {
|
|
425
|
+
project: projectArgument,
|
|
426
|
+
path: z.string().describe('PHP file inside the project, e.g. "app/Models/User.php"'),
|
|
427
|
+
line: z
|
|
428
|
+
.number()
|
|
429
|
+
.int()
|
|
430
|
+
.min(1)
|
|
431
|
+
.describe('The types are those right before this line runs; it must start a statement'),
|
|
432
|
+
expressions: z
|
|
433
|
+
.array(z.string())
|
|
434
|
+
.min(1)
|
|
435
|
+
.max(MAX_EXPRESSIONS)
|
|
436
|
+
.describe('PHP expressions, one per entry, e.g. ["$user", "$request->input(\'id\')"]'),
|
|
437
|
+
config: configArgument,
|
|
438
|
+
memoryLimit: z.string().optional(),
|
|
439
|
+
timeoutSeconds: z.number().int().positive().max(1800).optional(),
|
|
440
|
+
},
|
|
441
|
+
outputSchema: {
|
|
442
|
+
project: z.string(),
|
|
443
|
+
file: z.string().describe('Path relative to the project root'),
|
|
444
|
+
line: z.number(),
|
|
445
|
+
types: z.array(z.object({
|
|
446
|
+
expression: z.string(),
|
|
447
|
+
type: nullable(z.string()).describe('As PHPStan infers it; null if PHPStan reported none'),
|
|
448
|
+
problems: z
|
|
449
|
+
.array(z.object({ identifier: nullable(z.string()), message: z.string() }))
|
|
450
|
+
.describe('Other messages on the line of this dump, e.g. why the type is *ERROR*'),
|
|
451
|
+
})),
|
|
452
|
+
parseErrors: z
|
|
453
|
+
.array(z.object({
|
|
454
|
+
line: nullable(z.number()).describe('Line number in the original file'),
|
|
455
|
+
inserted: z.boolean().describe('Whether the error is on one of the inserted lines'),
|
|
456
|
+
message: z.string(),
|
|
457
|
+
}))
|
|
458
|
+
.describe('Not empty if the inserted lines are not at a place where a statement can go'),
|
|
459
|
+
generalErrors: z.array(z.string()),
|
|
460
|
+
warnings: z.array(z.string()),
|
|
461
|
+
omitted: z.object({ parseErrors: z.number(), generalErrors: z.number(), warnings: z.number() }),
|
|
462
|
+
},
|
|
463
|
+
annotations: readOnly(),
|
|
464
|
+
}, async (args, extra) => {
|
|
465
|
+
const begin = Date.now();
|
|
466
|
+
try {
|
|
467
|
+
const resolved = resolveProject(args.project, roots);
|
|
468
|
+
log(server, 'debug', { event: 'type inspection started', project: resolved.path });
|
|
469
|
+
const report = await inspectType(resolved, { path: args.path, line: args.line, expressions: args.expressions }, { ...common(resolved, args), signal: extra.signal });
|
|
470
|
+
log(server, 'info', {
|
|
471
|
+
event: 'type inspected',
|
|
472
|
+
project: resolved.path,
|
|
473
|
+
expressions: report.types.length,
|
|
474
|
+
parseErrors: report.parseErrors.length,
|
|
475
|
+
durationMs: Date.now() - begin,
|
|
476
|
+
});
|
|
477
|
+
return {
|
|
478
|
+
content: [{ type: 'text', text: renderTypes(report) }],
|
|
479
|
+
structuredContent: { ...report },
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
return toFailure(error);
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
}
|
|
411
487
|
//# sourceMappingURL=inspect.js.map
|