@0x1f320.sh/why-did-you-render-mcp 1.0.0-dev.14 → 1.0.0-dev.16
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/dist/server/index.js +98 -8
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -228,6 +228,40 @@ var RenderStore = class {
|
|
|
228
228
|
for (const f of this.jsonlFiles()) unlinkSync(join(this.dir, f));
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
+
clearRendersByComponent(component, projectId) {
|
|
232
|
+
this.flush(projectId);
|
|
233
|
+
const files = projectId ? this.projectFiles(projectId) : this.jsonlFiles();
|
|
234
|
+
let removed = 0;
|
|
235
|
+
for (const f of files) {
|
|
236
|
+
const filePath = join(this.dir, f);
|
|
237
|
+
const renders = readJsonl(filePath);
|
|
238
|
+
const before = renders.length;
|
|
239
|
+
const remaining = renders.filter((r) => r.displayName !== component);
|
|
240
|
+
removed += before - remaining.length;
|
|
241
|
+
if (remaining.length === 0) {
|
|
242
|
+
unlinkSync(filePath);
|
|
243
|
+
this.clearBuffersForFile(f);
|
|
244
|
+
} else if (remaining.length < before) {
|
|
245
|
+
this.rewriteFile(filePath, remaining);
|
|
246
|
+
this.clearBuffersForFile(f);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return removed;
|
|
250
|
+
}
|
|
251
|
+
clearRendersByCommit(beforeCommit, projectId) {
|
|
252
|
+
this.flush(projectId);
|
|
253
|
+
const files = projectId ? this.projectFiles(projectId) : this.jsonlFiles();
|
|
254
|
+
let deleted = 0;
|
|
255
|
+
for (const f of files) {
|
|
256
|
+
const parsed = this.parseFilename(f);
|
|
257
|
+
if (parsed?.commitId != null && parsed.commitId < beforeCommit) {
|
|
258
|
+
unlinkSync(join(this.dir, f));
|
|
259
|
+
this.clearBuffersForFile(f);
|
|
260
|
+
deleted++;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return deleted;
|
|
264
|
+
}
|
|
231
265
|
getProjects() {
|
|
232
266
|
this.flush();
|
|
233
267
|
const projects = /* @__PURE__ */ new Set();
|
|
@@ -273,7 +307,19 @@ var RenderStore = class {
|
|
|
273
307
|
for (const r of renders) {
|
|
274
308
|
summary[r.project] ??= {};
|
|
275
309
|
const project = summary[r.project];
|
|
276
|
-
project[r.displayName]
|
|
310
|
+
project[r.displayName] ??= {
|
|
311
|
+
count: 0,
|
|
312
|
+
reasons: {
|
|
313
|
+
props: 0,
|
|
314
|
+
state: 0,
|
|
315
|
+
hooks: 0
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
const entry = project[r.displayName];
|
|
319
|
+
entry.count++;
|
|
320
|
+
if (Array.isArray(r.reason.propsDifferences)) entry.reasons.props++;
|
|
321
|
+
if (Array.isArray(r.reason.stateDifferences)) entry.reasons.state++;
|
|
322
|
+
if (Array.isArray(r.reason.hookDifferences)) entry.reasons.hooks++;
|
|
277
323
|
}
|
|
278
324
|
return summary;
|
|
279
325
|
}
|
|
@@ -285,7 +331,19 @@ var RenderStore = class {
|
|
|
285
331
|
summary[r.project] ??= {};
|
|
286
332
|
summary[r.project][r.commitId] ??= {};
|
|
287
333
|
const commit = summary[r.project][r.commitId];
|
|
288
|
-
commit[r.displayName]
|
|
334
|
+
commit[r.displayName] ??= {
|
|
335
|
+
count: 0,
|
|
336
|
+
reasons: {
|
|
337
|
+
props: 0,
|
|
338
|
+
state: 0,
|
|
339
|
+
hooks: 0
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
const entry = commit[r.displayName];
|
|
343
|
+
entry.count++;
|
|
344
|
+
if (Array.isArray(r.reason.propsDifferences)) entry.reasons.props++;
|
|
345
|
+
if (Array.isArray(r.reason.stateDifferences)) entry.reasons.state++;
|
|
346
|
+
if (Array.isArray(r.reason.hookDifferences)) entry.reasons.hooks++;
|
|
289
347
|
}
|
|
290
348
|
return summary;
|
|
291
349
|
}
|
|
@@ -304,6 +362,25 @@ var RenderStore = class {
|
|
|
304
362
|
}
|
|
305
363
|
return result;
|
|
306
364
|
}
|
|
365
|
+
rewriteFile(filePath, renders) {
|
|
366
|
+
writeFileSync(filePath, `${renders.map((r) => JSON.stringify(r)).join("\n")}\n`);
|
|
367
|
+
}
|
|
368
|
+
clearBuffersForFile(filename) {
|
|
369
|
+
const parsed = this.parseFilename(filename);
|
|
370
|
+
if (!parsed) return;
|
|
371
|
+
for (const [bk, meta] of this.bufferMeta) {
|
|
372
|
+
if (sanitizeProjectId(meta.projectId) !== parsed.projectSanitized) continue;
|
|
373
|
+
if (!(parsed.commitId != null ? meta.commitId === parsed.commitId : meta.commitId == null)) continue;
|
|
374
|
+
this.buffers.delete(bk);
|
|
375
|
+
this.dicts.delete(bk);
|
|
376
|
+
this.bufferMeta.delete(bk);
|
|
377
|
+
const timer = this.timers.get(bk);
|
|
378
|
+
if (timer) {
|
|
379
|
+
clearTimeout(timer);
|
|
380
|
+
this.timers.delete(bk);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
307
384
|
bufferKey(projectId, commitId) {
|
|
308
385
|
return `${projectId}\0${commitId ?? NOCOMMIT}`;
|
|
309
386
|
}
|
|
@@ -374,11 +451,17 @@ function textResult(text) {
|
|
|
374
451
|
function register$6(server) {
|
|
375
452
|
server.registerTool("clear_renders", {
|
|
376
453
|
title: "Clear Renders",
|
|
377
|
-
description: "Clears collected render data. If multiple projects are active and no project is specified, the tool will ask you to disambiguate.",
|
|
378
|
-
inputSchema: {
|
|
379
|
-
|
|
454
|
+
description: "Clears collected render data. Supports filtering by component name or by commit ID threshold. When no filter is given, clears all data. If multiple projects are active and no project is specified, the tool will ask you to disambiguate.",
|
|
455
|
+
inputSchema: {
|
|
456
|
+
project: z.string().optional().describe("Project identifier (the browser's origin URL, e.g. http://localhost:3000). Omit to auto-detect."),
|
|
457
|
+
component: z.string().optional().describe("Clear only renders for this component (by displayName)."),
|
|
458
|
+
beforeCommit: z.number().optional().describe("Clear all renders from commits with an ID strictly less than this value.")
|
|
459
|
+
}
|
|
460
|
+
}, async ({ project, component, beforeCommit }) => {
|
|
380
461
|
const resolved = resolveProject(project);
|
|
381
462
|
if (resolved.error) return textResult(resolved.error);
|
|
463
|
+
if (component) return textResult(`Cleared ${store.clearRendersByComponent(component, resolved.projectId)} render(s) for component "${component}".`);
|
|
464
|
+
if (beforeCommit != null) return textResult(`Cleared renders from ${store.clearRendersByCommit(beforeCommit, resolved.projectId)} commit file(s) before commit #${beforeCommit}.`);
|
|
382
465
|
store.clearRenders(resolved.projectId);
|
|
383
466
|
return textResult(resolved.projectId ? `Render data cleared for ${resolved.projectId}.` : "All render data cleared.");
|
|
384
467
|
});
|
|
@@ -428,13 +511,20 @@ function register$3(server) {
|
|
|
428
511
|
return aggregateSummary(resolved.projectId);
|
|
429
512
|
});
|
|
430
513
|
}
|
|
514
|
+
function formatReasons(reasons) {
|
|
515
|
+
const parts = [];
|
|
516
|
+
if (reasons.props > 0) parts.push(`props: ${reasons.props}`);
|
|
517
|
+
if (reasons.state > 0) parts.push(`state: ${reasons.state}`);
|
|
518
|
+
if (reasons.hooks > 0) parts.push(`hooks: ${reasons.hooks}`);
|
|
519
|
+
return parts.length > 0 ? ` — ${parts.join(", ")}` : "";
|
|
520
|
+
}
|
|
431
521
|
function aggregateSummary(projectId) {
|
|
432
522
|
const summary = store.getSummary(projectId);
|
|
433
523
|
if (Object.keys(summary).length === 0) return textResult("No renders recorded yet.");
|
|
434
524
|
const lines = [];
|
|
435
525
|
for (const [proj, components] of Object.entries(summary)) {
|
|
436
526
|
lines.push(`[${proj}]`);
|
|
437
|
-
for (const [name, count] of Object.entries(components)) lines.push(` ${name}: ${count} re-render(s)`);
|
|
527
|
+
for (const [name, { count, reasons }] of Object.entries(components)) lines.push(` ${name}: ${count} re-render(s)${formatReasons(reasons)}`);
|
|
438
528
|
}
|
|
439
529
|
return textResult(`Re-render summary:\n\n${lines.join("\n")}`);
|
|
440
530
|
}
|
|
@@ -447,9 +537,9 @@ function commitSummary(projectId) {
|
|
|
447
537
|
const sortedCommitIds = Object.keys(commits).map(Number).sort((a, b) => a - b);
|
|
448
538
|
for (const commitId of sortedCommitIds) {
|
|
449
539
|
const components = commits[commitId];
|
|
450
|
-
const total = Object.values(components).reduce((s, c) => s + c, 0);
|
|
540
|
+
const total = Object.values(components).reduce((s, c) => s + c.count, 0);
|
|
451
541
|
lines.push(` Commit #${commitId} (${total} re-render(s)):`);
|
|
452
|
-
for (const [name, count] of Object.entries(components)) lines.push(` ${name}: ${count}`);
|
|
542
|
+
for (const [name, { count, reasons }] of Object.entries(components)) lines.push(` ${name}: ${count}${formatReasons(reasons)}`);
|
|
453
543
|
}
|
|
454
544
|
}
|
|
455
545
|
return textResult(`Re-render summary (by commit):\n\n${lines.join("\n")}`);
|
package/package.json
CHANGED