mirror of
https://github.com/millionco/react-doctor.git
synced 2026-09-14 20:00:24 +08:00
8c2f03aea9
* feat: make React cleanup first-class * refactor: remove editor integrations * fix: harden React cleanup analysis * fix: detect default export duplication roots * fix: unwrap typed duplication roots * feat: add opt-in project analysis rules * fix: canonicalize project analysis paths * fix: harden project analysis precision * fix: recognize cross-platform project entries * fix: eliminate project analysis false positives * fix: harden project analysis reachability * fix: canonicalize project analysis inputs * fix: resolve project analysis review findings * fix: eliminate residual project analysis false positives * fix: ignore commented registry previews * fix: eliminate project analysis false positives * fix: normalize project analysis paths across platforms * fix: normalize Nextra theme path identity * test: canonicalize convention fixture paths * fix: preserve project analysis provenance * fix: harden project analysis precision * fix: honor project analysis boundaries * fix: recognize conditional config plugins * fix: recognize executable project references * fix: recognize Stencil tool contracts * fix: recognize nested tool references * fix: recognize project setup contracts * fix: recognize generated and local package consumers * fix: recognize static template package references * fix: recognize nested package runtime contracts * fix: close project analysis parser gaps * fix: parse project conventions structurally * refactor: replace structural scanners with parsers * fix: recognize functional Next CSS config * fix: close remaining project analysis gaps * fix: apply tag filters to project analysis * fix: preserve embedded source positions * fix: validate static config helper bindings * fix: bound runtime directory discovery * fix: close final dependency analysis gaps * fix: preserve declaration dependency references * chore: refresh generated rule metadata * fix: make project analysis portable and bounded * test: stabilize cleanup scaling guard * refactor: parse project syntax with oxc * fix: normalize native filesystem paths * fix: separate path identity from report paths * fix: match project files by filesystem identity * fix: match build glob files by package identity * fix: use native path keys for file identity * fix: canonicalize Windows file identities * fix: canonicalize package ownership paths * test: inspect Windows path identities * test: trace Windows package ownership * fix: keep Windows path identities consistent * fix: classify test contracts by normalized path * fix: scope test contracts by canonical package path * fix: keep test package graphs conservative * test: keep React complexity advisory
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
import * as fs from "node:fs";
|
|
import os from "node:os";
|
|
import * as path from "node:path";
|
|
import { afterAll, afterEach, describe, expect, it, vi } from "vite-plus/test";
|
|
import { diagnose } from "../src/index.js";
|
|
import { setupReactProject } from "./regressions/_helpers.js";
|
|
|
|
const temporaryRoot = fs.mkdtempSync(path.join(os.tmpdir(), "rd-diff-fast-path-"));
|
|
|
|
afterAll(() => {
|
|
fs.rmSync(temporaryRoot, { recursive: true, force: true });
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
const stubOfflineScore = () =>
|
|
vi.stubGlobal(
|
|
"fetch",
|
|
vi.fn(
|
|
async () =>
|
|
new Response(JSON.stringify({ score: 100, label: "Perfect" }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
}),
|
|
),
|
|
);
|
|
|
|
const duplicatedJsxFixture = (caseIdentifier: string): string =>
|
|
setupReactProject(temporaryRoot, caseIdentifier, {
|
|
packageJsonExtras: { type: "module" },
|
|
files: {
|
|
"src/index.ts": "export const version = 1;\n",
|
|
"src/account.tsx": `export const Account = ({ value }: { value: string }) => (
|
|
<AccountScreen><Page><section><header><Title /></header><main><Value value={value} /></main><footer><Button /></footer></section></Page></AccountScreen>
|
|
);\n`,
|
|
"src/user.tsx": `export const User = ({ name }: { name: string }) => (
|
|
<UserScreen><Page><section><header><Title /></header><main><Value value={name} /></main><footer><Button /></footer></section></Page></UserScreen>
|
|
);\n`,
|
|
},
|
|
});
|
|
|
|
describe("diff maintainability focus", () => {
|
|
it("compares a changed file with unchanged duplicate counterparts", async () => {
|
|
stubOfflineScore();
|
|
const projectDirectory = duplicatedJsxFixture("changed-duplicate");
|
|
const result = await diagnose(projectDirectory, {
|
|
lint: false,
|
|
deadCode: true,
|
|
warnings: true,
|
|
includePaths: ["src/user.tsx"],
|
|
});
|
|
|
|
const diagnostic = result.diagnostics.find(
|
|
(candidate) => candidate.rule === "duplicate-jsx-subtree",
|
|
);
|
|
expect(diagnostic?.filePath).toBe("src/user.tsx");
|
|
expect(diagnostic?.relatedLocations?.[0].filePath).toBe("src/account.tsx");
|
|
});
|
|
|
|
it("does not report duplicate families untouched by the diff", async () => {
|
|
stubOfflineScore();
|
|
const projectDirectory = duplicatedJsxFixture("unrelated-change");
|
|
const result = await diagnose(projectDirectory, {
|
|
lint: false,
|
|
deadCode: true,
|
|
warnings: true,
|
|
includePaths: ["src/index.ts"],
|
|
});
|
|
|
|
expect(result.diagnostics.some((candidate) => candidate.rule === "duplicate-jsx-subtree")).toBe(
|
|
false,
|
|
);
|
|
});
|
|
});
|