import assert from "node:assert/strict"; import { execFileSync } from "node:child_process"; import { test } from "node:test"; import { parse } from "@typescript-eslint/parser"; import { ESLint } from "eslint"; const eslint = new ESLint({ fix: true }); function syntax(source) { const tree = parse(source, { sourceType: "module", ecmaFeatures: { jsx: true } }); return JSON.stringify(tree, (key, value) => ["loc", "range", "start", "end", "tokens", "comments"].includes(key) ? undefined : value ); } const source = `import { helper } from "example"; export interface Example { value: number } type Identifier = string; function first() { return 1; } function second() { return 2; } const arrow = () => 3; const other = () => 4; class Service { value = 1; enabled = true; constructor() {} first() { return this.value; } second() { return 2; } } function overloaded(value: string): string; function overloaded(value: number): number; function overloaded(value: string | number) { return value; } export function View() { const label = "Nombre"; return {label}; } `; test("el espaciado separa declaraciones y métodos sin cambiar la sintaxis ni las sobrecargas", async () => { const [result] = await eslint.lintText(source, { filePath: "apps/web/src/spacing-example.tsx" }); assert.ok(result); assert.equal(result.errorCount, 0); assert.ok(result.output); assert.match(result.output, /}\n\nfunction second/); assert.match(result.output, /const arrow = .*;\n\nconst other/); assert.match(result.output, /enabled = true;\n\n {2}constructor/); assert.match(result.output, /constructor\(\) {}\n\n {2}first/); assert.match(result.output, /value = 1;\n {2}enabled/); assert.match(result.output, /string;\nfunction overloaded/); assert.equal(syntax(result.output), syntax(source)); const [repeated] = await eslint.lintText(result.output, { filePath: "apps/web/src/spacing-example.tsx", }); assert.equal(repeated?.errorCount, 0); assert.equal(repeated?.output, undefined); }); test("la biblioteca de terceros queda excluida", async () => { assert.equal(await eslint.isPathIgnored("packages/shadcn-ui/src/components/button.tsx"), true); }); test("Biome y ESLint conservan el espaciado al repetir el formateo", async () => { const format = (text) => execFileSync( "pnpm", ["exec", "biome", "format", "--stdin-file-path=apps/web/src/spacing-example.tsx"], { input: text, encoding: "utf8" } ); const [spaced] = await eslint.lintText(format(source), { filePath: "apps/web/src/spacing-example.tsx", }); assert.ok(spaced); assert.equal(spaced.errorCount, 0); const output = spaced.output ?? format(source); const biomeOutput = format(output); const [repeated] = await eslint.lintText(biomeOutput, { filePath: "apps/web/src/spacing-example.tsx", }); assert.equal(repeated?.errorCount, 0); assert.equal(repeated?.output, undefined); assert.equal(syntax(output), syntax(biomeOutput)); });