pi-lens 3.6.3 → 3.6.4
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/package.json +3 -3
- package/tsconfig.json +1 -1
- package/clients/__tests__/file-time.test.js +0 -216
- package/clients/__tests__/file-time.test.ts +0 -276
- package/clients/__tests__/format-service.test.js +0 -245
- package/clients/__tests__/format-service.test.ts +0 -339
- package/clients/__tests__/formatters.test.js +0 -271
- package/clients/__tests__/formatters.test.ts +0 -401
- package/clients/agent-behavior-client.js +0 -110
- package/clients/agent-behavior-client.test.js +0 -94
- package/clients/agent-behavior-client.test.ts +0 -116
- package/clients/amain-types.js +0 -164
- package/clients/architect-client.js +0 -291
- package/clients/ast-grep-client.js +0 -253
- package/clients/ast-grep-parser.js +0 -84
- package/clients/ast-grep-rule-manager.js +0 -89
- package/clients/ast-grep-types.js +0 -9
- package/clients/auto-loop.js +0 -131
- package/clients/biome-client.js +0 -420
- package/clients/biome-client.test.js +0 -144
- package/clients/biome-client.test.ts +0 -163
- package/clients/cache/rule-cache.js +0 -72
- package/clients/cache-manager.js +0 -245
- package/clients/cache-manager.test.js +0 -197
- package/clients/cache-manager.test.ts +0 -299
- package/clients/complexity-client.js +0 -675
- package/clients/complexity-client.test.js +0 -234
- package/clients/complexity-client.test.ts +0 -255
- package/clients/config-validator.js +0 -465
- package/clients/dependency-checker.js +0 -325
- package/clients/dependency-checker.test.js +0 -60
- package/clients/dependency-checker.test.ts +0 -71
- package/clients/dispatch/__tests__/autofix-integration.test.js +0 -245
- package/clients/dispatch/__tests__/autofix-integration.test.ts +0 -300
- package/clients/dispatch/__tests__/runner-registration.test.js +0 -234
- package/clients/dispatch/__tests__/runner-registration.test.ts +0 -286
- package/clients/dispatch/debug.log +0 -1
- package/clients/dispatch/dispatcher.edge.test.js +0 -82
- package/clients/dispatch/dispatcher.edge.test.ts +0 -100
- package/clients/dispatch/dispatcher.format.test.js +0 -46
- package/clients/dispatch/dispatcher.format.test.ts +0 -58
- package/clients/dispatch/dispatcher.inline.test.js +0 -74
- package/clients/dispatch/dispatcher.inline.test.ts +0 -93
- package/clients/dispatch/dispatcher.js +0 -381
- package/clients/dispatch/dispatcher.test.js +0 -116
- package/clients/dispatch/dispatcher.test.ts +0 -149
- package/clients/dispatch/integration.js +0 -108
- package/clients/dispatch/plan.js +0 -183
- package/clients/dispatch/runners/architect.js +0 -83
- package/clients/dispatch/runners/architect.test.js +0 -138
- package/clients/dispatch/runners/architect.test.ts +0 -162
- package/clients/dispatch/runners/ast-grep-napi.js +0 -405
- package/clients/dispatch/runners/ast-grep-napi.test.js +0 -107
- package/clients/dispatch/runners/ast-grep-napi.test.ts +0 -129
- package/clients/dispatch/runners/ast-grep.js +0 -157
- package/clients/dispatch/runners/biome.js +0 -55
- package/clients/dispatch/runners/config-validation.js +0 -67
- package/clients/dispatch/runners/go-vet.js +0 -48
- package/clients/dispatch/runners/index.js +0 -47
- package/clients/dispatch/runners/lsp.js +0 -102
- package/clients/dispatch/runners/oxlint.js +0 -67
- package/clients/dispatch/runners/oxlint.test.js +0 -230
- package/clients/dispatch/runners/oxlint.test.ts +0 -303
- package/clients/dispatch/runners/pyright.js +0 -100
- package/clients/dispatch/runners/pyright.test.js +0 -98
- package/clients/dispatch/runners/pyright.test.ts +0 -121
- package/clients/dispatch/runners/python-slop.js +0 -97
- package/clients/dispatch/runners/python-slop.test.js +0 -203
- package/clients/dispatch/runners/python-slop.test.ts +0 -298
- package/clients/dispatch/runners/ruff.js +0 -48
- package/clients/dispatch/runners/rust-clippy.js +0 -102
- package/clients/dispatch/runners/scan_codebase.test.js +0 -89
- package/clients/dispatch/runners/scan_codebase.test.ts +0 -105
- package/clients/dispatch/runners/shellcheck.js +0 -147
- package/clients/dispatch/runners/shellcheck.test.js +0 -98
- package/clients/dispatch/runners/shellcheck.test.ts +0 -129
- package/clients/dispatch/runners/similarity.js +0 -230
- package/clients/dispatch/runners/spellcheck.js +0 -106
- package/clients/dispatch/runners/spellcheck.test.js +0 -158
- package/clients/dispatch/runners/spellcheck.test.ts +0 -214
- package/clients/dispatch/runners/tree-sitter.js +0 -246
- package/clients/dispatch/runners/ts-lsp.js +0 -125
- package/clients/dispatch/runners/ts-slop.js +0 -113
- package/clients/dispatch/runners/type-safety.js +0 -142
- package/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -134
- package/clients/dispatch/runners/utils/runner-helpers.js +0 -115
- package/clients/dispatch/runners/utils.js +0 -51
- package/clients/dispatch/runners/yaml-rule-parser.js +0 -360
- package/clients/dispatch/types.js +0 -16
- package/clients/dispatch/utils/format-utils.js +0 -44
- package/clients/dogfood.test.js +0 -201
- package/clients/dogfood.test.ts +0 -269
- package/clients/file-kinds.js +0 -177
- package/clients/file-kinds.test.js +0 -169
- package/clients/file-kinds.test.ts +0 -210
- package/clients/file-time.js +0 -152
- package/clients/file-utils.js +0 -40
- package/clients/fix-scanners.js +0 -204
- package/clients/format-service.js +0 -184
- package/clients/formatters.js +0 -488
- package/clients/go-client.js +0 -203
- package/clients/go-client.test.js +0 -127
- package/clients/go-client.test.ts +0 -143
- package/clients/installer/index.js +0 -403
- package/clients/interviewer-templates.js +0 -75
- package/clients/interviewer.js +0 -173
- package/clients/jscpd-client.js +0 -196
- package/clients/jscpd-client.test.js +0 -127
- package/clients/jscpd-client.test.ts +0 -145
- package/clients/knip-client.js +0 -239
- package/clients/knip-client.test.js +0 -112
- package/clients/knip-client.test.ts +0 -128
- package/clients/latency-logger.js +0 -40
- package/clients/lsp/__tests__/client.test.js +0 -310
- package/clients/lsp/__tests__/client.test.ts +0 -412
- package/clients/lsp/__tests__/config.test.js +0 -167
- package/clients/lsp/__tests__/config.test.ts +0 -217
- package/clients/lsp/__tests__/error-recovery.test.js +0 -213
- package/clients/lsp/__tests__/error-recovery.test.ts +0 -279
- package/clients/lsp/__tests__/integration.test.js +0 -127
- package/clients/lsp/__tests__/integration.test.ts +0 -160
- package/clients/lsp/__tests__/launch.test.js +0 -313
- package/clients/lsp/__tests__/launch.test.ts +0 -394
- package/clients/lsp/__tests__/server.test.js +0 -259
- package/clients/lsp/__tests__/server.test.ts +0 -332
- package/clients/lsp/__tests__/service.test.js +0 -438
- package/clients/lsp/__tests__/service.test.ts +0 -530
- package/clients/lsp/client.js +0 -350
- package/clients/lsp/config.js +0 -112
- package/clients/lsp/index.js +0 -318
- package/clients/lsp/installer/index.js +0 -391
- package/clients/lsp/interactive-install.js +0 -221
- package/clients/lsp/language.js +0 -170
- package/clients/lsp/launch.js +0 -329
- package/clients/lsp/lsp/launch.js +0 -116
- package/clients/lsp/lsp/server.js +0 -532
- package/clients/lsp/lsp-index.js +0 -10
- package/clients/lsp/path-utils.js +0 -5
- package/clients/lsp/server.js +0 -725
- package/clients/lsp/test-py-spawn/requirements.txt +0 -1
- package/clients/lsp/test-py-spawn/test.py +0 -3
- package/clients/lsp/test-py-svc/requirements.txt +0 -1
- package/clients/lsp/test-py-svc/test.py +0 -3
- package/clients/lsp/test-python-project/requirements.txt +0 -1
- package/clients/lsp/test-python-project/test.py +0 -5
- package/clients/metrics-client.js +0 -107
- package/clients/metrics-client.test.js +0 -128
- package/clients/metrics-client.test.ts +0 -163
- package/clients/metrics-history.js +0 -367
- package/clients/path-utils.js +0 -142
- package/clients/pipeline.js +0 -272
- package/clients/production-readiness.js +0 -522
- package/clients/project-index.js +0 -255
- package/clients/project-metadata.js +0 -531
- package/clients/ruff-client.js +0 -325
- package/clients/ruff-client.test.js +0 -132
- package/clients/ruff-client.test.ts +0 -153
- package/clients/rules-scanner.js +0 -97
- package/clients/runner-tracker.js +0 -152
- package/clients/rust-client.js +0 -205
- package/clients/rust-client.test.js +0 -108
- package/clients/rust-client.test.ts +0 -130
- package/clients/safe-spawn-async.js +0 -163
- package/clients/safe-spawn.js +0 -241
- package/clients/sanitize.js +0 -291
- package/clients/sanitize.test.js +0 -177
- package/clients/sanitize.test.ts +0 -223
- package/clients/scan-architectural-debt.js +0 -167
- package/clients/scan-utils.js +0 -83
- package/clients/secrets-scanner.js +0 -119
- package/clients/secrets-scanner.test.js +0 -100
- package/clients/secrets-scanner.test.ts +0 -113
- package/clients/sg-runner.js +0 -292
- package/clients/state-matrix.js +0 -160
- package/clients/subprocess-client.js +0 -65
- package/clients/symbol-types.js +0 -5
- package/clients/test-runner-client.js +0 -523
- package/clients/test-runner-client.test.js +0 -192
- package/clients/test-runner-client.test.ts +0 -253
- package/clients/test-utils.js +0 -27
- package/clients/test-utils.ts +0 -36
- package/clients/todo-scanner.js +0 -200
- package/clients/todo-scanner.test.js +0 -301
- package/clients/todo-scanner.test.ts +0 -352
- package/clients/tool-availability.js +0 -207
- package/clients/tree-sitter-client.js +0 -601
- package/clients/tree-sitter-query-loader.js +0 -355
- package/clients/tree-sitter-symbol-extractor.js +0 -289
- package/clients/ts-service.js +0 -129
- package/clients/type-coverage-client.js +0 -127
- package/clients/type-coverage-client.test.js +0 -105
- package/clients/type-coverage-client.test.ts +0 -125
- package/clients/type-safety-client.js +0 -138
- package/clients/types.js +0 -11
- package/clients/typescript-client.codefix.test.js +0 -157
- package/clients/typescript-client.codefix.test.ts +0 -186
- package/clients/typescript-client.js +0 -509
- package/clients/typescript-client.test.js +0 -105
- package/clients/typescript-client.test.ts +0 -126
- package/commands/booboo.js +0 -1007
- package/commands/fix-from-booboo.js +0 -398
- package/commands/fix-simplified.js +0 -618
- package/commands/rate.js +0 -281
- package/commands/rate.test.js +0 -119
- package/commands/rate.test.ts +0 -131
- package/commands/refactor.js +0 -130
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Format Service Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests concurrent formatter execution via Effect-TS
|
|
5
|
-
* and FileTime integration for safety.
|
|
6
|
-
*/
|
|
7
|
-
import * as fs from "node:fs";
|
|
8
|
-
import * as path from "node:path";
|
|
9
|
-
import { dirname } from "node:path";
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
11
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
12
|
-
import { FileTimeError } from "../file-time.js";
|
|
13
|
-
import { FormatService, getFormatService, resetFormatService, } from "../format-service.js";
|
|
14
|
-
import { clearAllSessions } from "../file-time.js";
|
|
15
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
-
const __dirname = dirname(__filename);
|
|
17
|
-
const TEST_DIR = path.join(__dirname, "..", "..", "test-format-service");
|
|
18
|
-
describe("FormatService", () => {
|
|
19
|
-
let formatService;
|
|
20
|
-
const sessionID = "test-format-session";
|
|
21
|
-
beforeEach(() => {
|
|
22
|
-
resetFormatService();
|
|
23
|
-
clearAllSessions(); // Clear FileTime global state for test isolation
|
|
24
|
-
formatService = new FormatService(sessionID, true);
|
|
25
|
-
if (fs.existsSync(TEST_DIR)) {
|
|
26
|
-
fs.rmSync(TEST_DIR, { recursive: true });
|
|
27
|
-
}
|
|
28
|
-
fs.mkdirSync(TEST_DIR, { recursive: true });
|
|
29
|
-
});
|
|
30
|
-
afterEach(() => {
|
|
31
|
-
resetFormatService();
|
|
32
|
-
clearAllSessions(); // Clear FileTime global state for test isolation
|
|
33
|
-
if (fs.existsSync(TEST_DIR)) {
|
|
34
|
-
fs.rmSync(TEST_DIR, { recursive: true });
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
describe("formatFile()", () => {
|
|
38
|
-
it("should skip formatting when disabled", async () => {
|
|
39
|
-
const disabledService = new FormatService(sessionID, false);
|
|
40
|
-
const testFile = path.join(TEST_DIR, "disabled.txt");
|
|
41
|
-
fs.writeFileSync(testFile, "content");
|
|
42
|
-
const result = await disabledService.formatFile(testFile);
|
|
43
|
-
expect(result.formatters).toEqual([]);
|
|
44
|
-
expect(result.anyChanged).toBe(false);
|
|
45
|
-
expect(result.allSucceeded).toBe(true);
|
|
46
|
-
});
|
|
47
|
-
it("should skip formatting with skip option", async () => {
|
|
48
|
-
const testFile = path.join(TEST_DIR, "skipped.txt");
|
|
49
|
-
fs.writeFileSync(testFile, "content");
|
|
50
|
-
const result = await formatService.formatFile(testFile, { skip: true });
|
|
51
|
-
expect(result.formatters).toEqual([]);
|
|
52
|
-
expect(result.anyChanged).toBe(false);
|
|
53
|
-
expect(result.allSucceeded).toBe(true);
|
|
54
|
-
});
|
|
55
|
-
it("should skip when file modified externally", async () => {
|
|
56
|
-
const testFile = path.join(TEST_DIR, "external.txt");
|
|
57
|
-
fs.writeFileSync(testFile, "original");
|
|
58
|
-
// Record read
|
|
59
|
-
formatService.recordRead(testFile);
|
|
60
|
-
// Modify externally
|
|
61
|
-
fs.writeFileSync(testFile, "modified");
|
|
62
|
-
const result = await formatService.formatFile(testFile);
|
|
63
|
-
expect(result.formatters).toEqual([]);
|
|
64
|
-
expect(result.anyChanged).toBe(false);
|
|
65
|
-
expect(result.allSucceeded).toBe(false);
|
|
66
|
-
});
|
|
67
|
-
it("should format TypeScript file with biome config", async () => {
|
|
68
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), '{"formatter": {}}');
|
|
69
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
70
|
-
fs.writeFileSync(tsFile, "const x=1;");
|
|
71
|
-
// Record read so format service knows initial state
|
|
72
|
-
formatService.recordRead(tsFile);
|
|
73
|
-
const result = await formatService.formatFile(tsFile);
|
|
74
|
-
expect(result.filePath).toBe(tsFile);
|
|
75
|
-
expect(result.formatters.some((f) => f.name === "biome")).toBe(true);
|
|
76
|
-
});
|
|
77
|
-
it("should format Python file with ruff config", async () => {
|
|
78
|
-
fs.writeFileSync(path.join(TEST_DIR, "pyproject.toml"), "[tool.ruff]\nline-length = 100");
|
|
79
|
-
const pyFile = path.join(TEST_DIR, "test.py");
|
|
80
|
-
fs.writeFileSync(pyFile, "x=1");
|
|
81
|
-
// Record read so format service knows initial state
|
|
82
|
-
formatService.recordRead(pyFile);
|
|
83
|
-
const result = await formatService.formatFile(pyFile);
|
|
84
|
-
expect(result.filePath).toBe(pyFile);
|
|
85
|
-
expect(result.formatters.some((f) => f.name === "ruff")).toBe(true);
|
|
86
|
-
});
|
|
87
|
-
it("should run multiple formatters for same file", async () => {
|
|
88
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
89
|
-
fs.writeFileSync(path.join(TEST_DIR, "package.json"), JSON.stringify({ devDependencies: { prettier: "^3.0.0" } }));
|
|
90
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
91
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
92
|
-
formatService.recordRead(tsFile);
|
|
93
|
-
const result = await formatService.formatFile(tsFile);
|
|
94
|
-
const names = result.formatters.map((f) => f.name);
|
|
95
|
-
expect(names).toContain("biome");
|
|
96
|
-
});
|
|
97
|
-
it("should return empty result for unsupported file", async () => {
|
|
98
|
-
const txtFile = path.join(TEST_DIR, "test.txt");
|
|
99
|
-
fs.writeFileSync(txtFile, "content");
|
|
100
|
-
formatService.recordRead(txtFile);
|
|
101
|
-
const result = await formatService.formatFile(txtFile);
|
|
102
|
-
expect(result.formatters).toEqual([]);
|
|
103
|
-
expect(result.anyChanged).toBe(false);
|
|
104
|
-
expect(result.allSucceeded).toBe(true);
|
|
105
|
-
});
|
|
106
|
-
it("should record FileTime after formatting", async () => {
|
|
107
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
108
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
109
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
110
|
-
formatService.recordRead(tsFile);
|
|
111
|
-
await formatService.formatFile(tsFile);
|
|
112
|
-
expect(() => formatService.assertUnchanged(tsFile)).not.toThrow();
|
|
113
|
-
});
|
|
114
|
-
it("should report success/failure for each formatter", async () => {
|
|
115
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
116
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
117
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
118
|
-
formatService.recordRead(tsFile);
|
|
119
|
-
const result = await formatService.formatFile(tsFile);
|
|
120
|
-
for (const formatter of result.formatters) {
|
|
121
|
-
expect(formatter).toHaveProperty("name");
|
|
122
|
-
expect(formatter).toHaveProperty("success");
|
|
123
|
-
expect(formatter).toHaveProperty("changed");
|
|
124
|
-
expect(typeof formatter.success).toBe("boolean");
|
|
125
|
-
expect(typeof formatter.changed).toBe("boolean");
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
it("should re-read file content after formatting", async () => {
|
|
129
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
130
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
131
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
132
|
-
formatService.recordRead(tsFile);
|
|
133
|
-
const _result = await formatService.formatFile(tsFile);
|
|
134
|
-
const after = fs.readFileSync(tsFile, "utf-8");
|
|
135
|
-
expect(after).toBeDefined();
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
describe("assertUnchanged()", () => {
|
|
139
|
-
it("should not throw for unchanged files", async () => {
|
|
140
|
-
const testFile = path.join(TEST_DIR, "unchanged.txt");
|
|
141
|
-
fs.writeFileSync(testFile, "content");
|
|
142
|
-
formatService.recordRead(testFile);
|
|
143
|
-
expect(() => formatService.assertUnchanged(testFile)).not.toThrow();
|
|
144
|
-
});
|
|
145
|
-
it("should throw FileTimeError when file modified", async () => {
|
|
146
|
-
const testFile = path.join(TEST_DIR, "modified.txt");
|
|
147
|
-
fs.writeFileSync(testFile, "original");
|
|
148
|
-
formatService.recordRead(testFile);
|
|
149
|
-
fs.writeFileSync(testFile, "changed");
|
|
150
|
-
expect(() => formatService.assertUnchanged(testFile)).toThrow(FileTimeError);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
describe("hasChanged()", () => {
|
|
154
|
-
it("should return false for unchanged files", async () => {
|
|
155
|
-
const testFile = path.join(TEST_DIR, "unchanged-check.txt");
|
|
156
|
-
fs.writeFileSync(testFile, "content");
|
|
157
|
-
formatService.recordRead(testFile);
|
|
158
|
-
expect(formatService.hasChanged(testFile)).toBe(false);
|
|
159
|
-
});
|
|
160
|
-
it("should return true when file modified", async () => {
|
|
161
|
-
const testFile = path.join(TEST_DIR, "changed-check.txt");
|
|
162
|
-
fs.writeFileSync(testFile, "original");
|
|
163
|
-
formatService.recordRead(testFile);
|
|
164
|
-
// Small delay to ensure different mtime (Windows has ~16ms resolution)
|
|
165
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
166
|
-
fs.writeFileSync(testFile, "modified");
|
|
167
|
-
expect(formatService.hasChanged(testFile)).toBe(true);
|
|
168
|
-
});
|
|
169
|
-
it("should return true for unread files", async () => {
|
|
170
|
-
const testFile = path.join(TEST_DIR, "never-read.txt");
|
|
171
|
-
fs.writeFileSync(testFile, "content");
|
|
172
|
-
expect(formatService.hasChanged(testFile)).toBe(true);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
describe("recordRead()", () => {
|
|
176
|
-
it("should record file read for tracking", async () => {
|
|
177
|
-
const testFile = path.join(TEST_DIR, "tracked.txt");
|
|
178
|
-
fs.writeFileSync(testFile, "content");
|
|
179
|
-
formatService.recordRead(testFile);
|
|
180
|
-
expect(formatService.hasChanged(testFile)).toBe(false);
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
describe("clearCache()", () => {
|
|
184
|
-
it("should clear formatter detection cache", async () => {
|
|
185
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
186
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
187
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
188
|
-
formatService.recordRead(tsFile);
|
|
189
|
-
await formatService.formatFile(tsFile);
|
|
190
|
-
formatService.clearCache();
|
|
191
|
-
await formatService.formatFile(tsFile);
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
describe("Concurrency", () => {
|
|
195
|
-
it("should handle multiple files concurrently", async () => {
|
|
196
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
197
|
-
const files = [
|
|
198
|
-
path.join(TEST_DIR, "file1.ts"),
|
|
199
|
-
path.join(TEST_DIR, "file2.ts"),
|
|
200
|
-
path.join(TEST_DIR, "file3.ts"),
|
|
201
|
-
];
|
|
202
|
-
for (const file of files) {
|
|
203
|
-
fs.writeFileSync(file, "const x = 1;");
|
|
204
|
-
formatService.recordRead(file);
|
|
205
|
-
}
|
|
206
|
-
const results = await Promise.all(files.map((f) => formatService.formatFile(f)));
|
|
207
|
-
expect(results).toHaveLength(3);
|
|
208
|
-
for (const result of results) {
|
|
209
|
-
expect(result.filePath).toBeDefined();
|
|
210
|
-
expect(result.formatters.length).toBeGreaterThan(0);
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
describe("getFormatService singleton", () => {
|
|
216
|
-
beforeEach(() => {
|
|
217
|
-
resetFormatService();
|
|
218
|
-
});
|
|
219
|
-
afterEach(() => {
|
|
220
|
-
resetFormatService();
|
|
221
|
-
});
|
|
222
|
-
it("should return singleton instance", () => {
|
|
223
|
-
const instance1 = getFormatService();
|
|
224
|
-
const instance2 = getFormatService();
|
|
225
|
-
expect(instance1).toBe(instance2);
|
|
226
|
-
});
|
|
227
|
-
it("should create new instance when session ID provided", () => {
|
|
228
|
-
const instance1 = getFormatService("session1");
|
|
229
|
-
const instance2 = getFormatService("session2");
|
|
230
|
-
expect(instance1).not.toBe(instance2);
|
|
231
|
-
});
|
|
232
|
-
it("should use cached instance regardless of enabled flag changes", () => {
|
|
233
|
-
const first = getFormatService("test", true);
|
|
234
|
-
const second = getFormatService("test", false);
|
|
235
|
-
expect(first).toBe(second);
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
describe("resetFormatService", () => {
|
|
239
|
-
it("should reset singleton instance", () => {
|
|
240
|
-
const instance1 = getFormatService();
|
|
241
|
-
resetFormatService();
|
|
242
|
-
const instance2 = getFormatService();
|
|
243
|
-
expect(instance1).not.toBe(instance2);
|
|
244
|
-
});
|
|
245
|
-
});
|
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Format Service Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests concurrent formatter execution via Effect-TS
|
|
5
|
-
* and FileTime integration for safety.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import * as fs from "node:fs";
|
|
9
|
-
import * as path from "node:path";
|
|
10
|
-
import { dirname } from "node:path";
|
|
11
|
-
import { fileURLToPath } from "node:url";
|
|
12
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
13
|
-
import { FileTimeError } from "../file-time.js";
|
|
14
|
-
import {
|
|
15
|
-
FormatService,
|
|
16
|
-
getFormatService,
|
|
17
|
-
resetFormatService,
|
|
18
|
-
} from "../format-service.js";
|
|
19
|
-
import { clearAllSessions } from "../file-time.js";
|
|
20
|
-
|
|
21
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
-
const __dirname = dirname(__filename);
|
|
23
|
-
|
|
24
|
-
const TEST_DIR = path.join(__dirname, "..", "..", "test-format-service");
|
|
25
|
-
|
|
26
|
-
describe("FormatService", () => {
|
|
27
|
-
let formatService: FormatService;
|
|
28
|
-
const sessionID = "test-format-session";
|
|
29
|
-
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
resetFormatService();
|
|
32
|
-
clearAllSessions(); // Clear FileTime global state for test isolation
|
|
33
|
-
formatService = new FormatService(sessionID, true);
|
|
34
|
-
|
|
35
|
-
if (fs.existsSync(TEST_DIR)) {
|
|
36
|
-
fs.rmSync(TEST_DIR, { recursive: true });
|
|
37
|
-
}
|
|
38
|
-
fs.mkdirSync(TEST_DIR, { recursive: true });
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
afterEach(() => {
|
|
42
|
-
resetFormatService();
|
|
43
|
-
clearAllSessions(); // Clear FileTime global state for test isolation
|
|
44
|
-
if (fs.existsSync(TEST_DIR)) {
|
|
45
|
-
fs.rmSync(TEST_DIR, { recursive: true });
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe("formatFile()", () => {
|
|
50
|
-
it("should skip formatting when disabled", async () => {
|
|
51
|
-
const disabledService = new FormatService(sessionID, false);
|
|
52
|
-
const testFile = path.join(TEST_DIR, "disabled.txt");
|
|
53
|
-
fs.writeFileSync(testFile, "content");
|
|
54
|
-
|
|
55
|
-
const result = await disabledService.formatFile(testFile);
|
|
56
|
-
|
|
57
|
-
expect(result.formatters).toEqual([]);
|
|
58
|
-
expect(result.anyChanged).toBe(false);
|
|
59
|
-
expect(result.allSucceeded).toBe(true);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("should skip formatting with skip option", async () => {
|
|
63
|
-
const testFile = path.join(TEST_DIR, "skipped.txt");
|
|
64
|
-
fs.writeFileSync(testFile, "content");
|
|
65
|
-
|
|
66
|
-
const result = await formatService.formatFile(testFile, { skip: true });
|
|
67
|
-
|
|
68
|
-
expect(result.formatters).toEqual([]);
|
|
69
|
-
expect(result.anyChanged).toBe(false);
|
|
70
|
-
expect(result.allSucceeded).toBe(true);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it("should skip when file modified externally", async () => {
|
|
74
|
-
const testFile = path.join(TEST_DIR, "external.txt");
|
|
75
|
-
fs.writeFileSync(testFile, "original");
|
|
76
|
-
|
|
77
|
-
// Record read
|
|
78
|
-
formatService.recordRead(testFile);
|
|
79
|
-
|
|
80
|
-
// Modify externally
|
|
81
|
-
fs.writeFileSync(testFile, "modified");
|
|
82
|
-
|
|
83
|
-
const result = await formatService.formatFile(testFile);
|
|
84
|
-
|
|
85
|
-
expect(result.formatters).toEqual([]);
|
|
86
|
-
expect(result.anyChanged).toBe(false);
|
|
87
|
-
expect(result.allSucceeded).toBe(false);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("should format TypeScript file with biome config", async () => {
|
|
91
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), '{"formatter": {}}');
|
|
92
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
93
|
-
fs.writeFileSync(tsFile, "const x=1;");
|
|
94
|
-
|
|
95
|
-
// Record read so format service knows initial state
|
|
96
|
-
formatService.recordRead(tsFile);
|
|
97
|
-
|
|
98
|
-
const result = await formatService.formatFile(tsFile);
|
|
99
|
-
|
|
100
|
-
expect(result.filePath).toBe(tsFile);
|
|
101
|
-
expect(result.formatters.some((f) => f.name === "biome")).toBe(true);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it("should format Python file with ruff config", async () => {
|
|
105
|
-
fs.writeFileSync(
|
|
106
|
-
path.join(TEST_DIR, "pyproject.toml"),
|
|
107
|
-
"[tool.ruff]\nline-length = 100",
|
|
108
|
-
);
|
|
109
|
-
const pyFile = path.join(TEST_DIR, "test.py");
|
|
110
|
-
fs.writeFileSync(pyFile, "x=1");
|
|
111
|
-
|
|
112
|
-
// Record read so format service knows initial state
|
|
113
|
-
formatService.recordRead(pyFile);
|
|
114
|
-
|
|
115
|
-
const result = await formatService.formatFile(pyFile);
|
|
116
|
-
|
|
117
|
-
expect(result.filePath).toBe(pyFile);
|
|
118
|
-
expect(result.formatters.some((f) => f.name === "ruff")).toBe(true);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it("should run multiple formatters for same file", async () => {
|
|
122
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
123
|
-
fs.writeFileSync(
|
|
124
|
-
path.join(TEST_DIR, "package.json"),
|
|
125
|
-
JSON.stringify({ devDependencies: { prettier: "^3.0.0" } }),
|
|
126
|
-
);
|
|
127
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
128
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
129
|
-
|
|
130
|
-
formatService.recordRead(tsFile);
|
|
131
|
-
|
|
132
|
-
const result = await formatService.formatFile(tsFile);
|
|
133
|
-
|
|
134
|
-
const names = result.formatters.map((f) => f.name);
|
|
135
|
-
expect(names).toContain("biome");
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("should return empty result for unsupported file", async () => {
|
|
139
|
-
const txtFile = path.join(TEST_DIR, "test.txt");
|
|
140
|
-
fs.writeFileSync(txtFile, "content");
|
|
141
|
-
|
|
142
|
-
formatService.recordRead(txtFile);
|
|
143
|
-
|
|
144
|
-
const result = await formatService.formatFile(txtFile);
|
|
145
|
-
|
|
146
|
-
expect(result.formatters).toEqual([]);
|
|
147
|
-
expect(result.anyChanged).toBe(false);
|
|
148
|
-
expect(result.allSucceeded).toBe(true);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("should record FileTime after formatting", async () => {
|
|
152
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
153
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
154
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
155
|
-
|
|
156
|
-
formatService.recordRead(tsFile);
|
|
157
|
-
|
|
158
|
-
await formatService.formatFile(tsFile);
|
|
159
|
-
|
|
160
|
-
expect(() => formatService.assertUnchanged(tsFile)).not.toThrow();
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it("should report success/failure for each formatter", async () => {
|
|
164
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
165
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
166
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
167
|
-
|
|
168
|
-
formatService.recordRead(tsFile);
|
|
169
|
-
|
|
170
|
-
const result = await formatService.formatFile(tsFile);
|
|
171
|
-
|
|
172
|
-
for (const formatter of result.formatters) {
|
|
173
|
-
expect(formatter).toHaveProperty("name");
|
|
174
|
-
expect(formatter).toHaveProperty("success");
|
|
175
|
-
expect(formatter).toHaveProperty("changed");
|
|
176
|
-
expect(typeof formatter.success).toBe("boolean");
|
|
177
|
-
expect(typeof formatter.changed).toBe("boolean");
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it("should re-read file content after formatting", async () => {
|
|
182
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
183
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
184
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
185
|
-
|
|
186
|
-
formatService.recordRead(tsFile);
|
|
187
|
-
|
|
188
|
-
const _result = await formatService.formatFile(tsFile);
|
|
189
|
-
|
|
190
|
-
const after = fs.readFileSync(tsFile, "utf-8");
|
|
191
|
-
expect(after).toBeDefined();
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
describe("assertUnchanged()", () => {
|
|
196
|
-
it("should not throw for unchanged files", async () => {
|
|
197
|
-
const testFile = path.join(TEST_DIR, "unchanged.txt");
|
|
198
|
-
fs.writeFileSync(testFile, "content");
|
|
199
|
-
formatService.recordRead(testFile);
|
|
200
|
-
|
|
201
|
-
expect(() => formatService.assertUnchanged(testFile)).not.toThrow();
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it("should throw FileTimeError when file modified", async () => {
|
|
205
|
-
const testFile = path.join(TEST_DIR, "modified.txt");
|
|
206
|
-
fs.writeFileSync(testFile, "original");
|
|
207
|
-
formatService.recordRead(testFile);
|
|
208
|
-
|
|
209
|
-
fs.writeFileSync(testFile, "changed");
|
|
210
|
-
|
|
211
|
-
expect(() => formatService.assertUnchanged(testFile)).toThrow(
|
|
212
|
-
FileTimeError,
|
|
213
|
-
);
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
describe("hasChanged()", () => {
|
|
218
|
-
it("should return false for unchanged files", async () => {
|
|
219
|
-
const testFile = path.join(TEST_DIR, "unchanged-check.txt");
|
|
220
|
-
fs.writeFileSync(testFile, "content");
|
|
221
|
-
formatService.recordRead(testFile);
|
|
222
|
-
|
|
223
|
-
expect(formatService.hasChanged(testFile)).toBe(false);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it("should return true when file modified", async () => {
|
|
227
|
-
const testFile = path.join(TEST_DIR, "changed-check.txt");
|
|
228
|
-
fs.writeFileSync(testFile, "original");
|
|
229
|
-
formatService.recordRead(testFile);
|
|
230
|
-
|
|
231
|
-
// Small delay to ensure different mtime (Windows has ~16ms resolution)
|
|
232
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
233
|
-
fs.writeFileSync(testFile, "modified");
|
|
234
|
-
|
|
235
|
-
expect(formatService.hasChanged(testFile)).toBe(true);
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it("should return true for unread files", async () => {
|
|
239
|
-
const testFile = path.join(TEST_DIR, "never-read.txt");
|
|
240
|
-
fs.writeFileSync(testFile, "content");
|
|
241
|
-
|
|
242
|
-
expect(formatService.hasChanged(testFile)).toBe(true);
|
|
243
|
-
});
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
describe("recordRead()", () => {
|
|
247
|
-
it("should record file read for tracking", async () => {
|
|
248
|
-
const testFile = path.join(TEST_DIR, "tracked.txt");
|
|
249
|
-
fs.writeFileSync(testFile, "content");
|
|
250
|
-
|
|
251
|
-
formatService.recordRead(testFile);
|
|
252
|
-
|
|
253
|
-
expect(formatService.hasChanged(testFile)).toBe(false);
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
describe("clearCache()", () => {
|
|
258
|
-
it("should clear formatter detection cache", async () => {
|
|
259
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
260
|
-
const tsFile = path.join(TEST_DIR, "test.ts");
|
|
261
|
-
fs.writeFileSync(tsFile, "const x = 1;");
|
|
262
|
-
formatService.recordRead(tsFile);
|
|
263
|
-
|
|
264
|
-
await formatService.formatFile(tsFile);
|
|
265
|
-
|
|
266
|
-
formatService.clearCache();
|
|
267
|
-
|
|
268
|
-
await formatService.formatFile(tsFile);
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
describe("Concurrency", () => {
|
|
273
|
-
it("should handle multiple files concurrently", async () => {
|
|
274
|
-
fs.writeFileSync(path.join(TEST_DIR, "biome.json"), "{}");
|
|
275
|
-
|
|
276
|
-
const files = [
|
|
277
|
-
path.join(TEST_DIR, "file1.ts"),
|
|
278
|
-
path.join(TEST_DIR, "file2.ts"),
|
|
279
|
-
path.join(TEST_DIR, "file3.ts"),
|
|
280
|
-
];
|
|
281
|
-
|
|
282
|
-
for (const file of files) {
|
|
283
|
-
fs.writeFileSync(file, "const x = 1;");
|
|
284
|
-
formatService.recordRead(file);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const results = await Promise.all(
|
|
288
|
-
files.map((f) => formatService.formatFile(f)),
|
|
289
|
-
);
|
|
290
|
-
|
|
291
|
-
expect(results).toHaveLength(3);
|
|
292
|
-
for (const result of results) {
|
|
293
|
-
expect(result.filePath).toBeDefined();
|
|
294
|
-
expect(result.formatters.length).toBeGreaterThan(0);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
describe("getFormatService singleton", () => {
|
|
301
|
-
beforeEach(() => {
|
|
302
|
-
resetFormatService();
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
afterEach(() => {
|
|
306
|
-
resetFormatService();
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
it("should return singleton instance", () => {
|
|
310
|
-
const instance1 = getFormatService();
|
|
311
|
-
const instance2 = getFormatService();
|
|
312
|
-
|
|
313
|
-
expect(instance1).toBe(instance2);
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
it("should create new instance when session ID provided", () => {
|
|
317
|
-
const instance1 = getFormatService("session1");
|
|
318
|
-
const instance2 = getFormatService("session2");
|
|
319
|
-
|
|
320
|
-
expect(instance1).not.toBe(instance2);
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it("should use cached instance regardless of enabled flag changes", () => {
|
|
324
|
-
const first = getFormatService("test", true);
|
|
325
|
-
const second = getFormatService("test", false);
|
|
326
|
-
|
|
327
|
-
expect(first).toBe(second);
|
|
328
|
-
});
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
describe("resetFormatService", () => {
|
|
332
|
-
it("should reset singleton instance", () => {
|
|
333
|
-
const instance1 = getFormatService();
|
|
334
|
-
resetFormatService();
|
|
335
|
-
const instance2 = getFormatService();
|
|
336
|
-
|
|
337
|
-
expect(instance1).not.toBe(instance2);
|
|
338
|
-
});
|
|
339
|
-
});
|