diff --git a/src/storage.ts b/src/storage.ts index aa95859..da2b87b 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -1,4 +1,4 @@ -import { readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs' +import { readFileSync, rmSync, writeFileSync } from 'node:fs' import { join } from 'node:path' import { env } from 'node:process' import * as vscode from 'vscode' @@ -6,6 +6,7 @@ import { traceData } from '../shared/src/traceData' import { getCurrentConfig } from './configuration' import { log } from './logger' import { state } from './appState' +import { getTraceFilesToDelete } from './traceFileDeletion' export function getProjectName(): string { if (state.projectName.value) @@ -137,18 +138,6 @@ function simpleHash(str: string) { export async function deleteTraceFiles(fileName: string, dirName?: string) { const deleteDirName = dirName ?? await getTraceDir() - if (fileName === '*') { - const files = readdirSync(deleteDirName) - for (const file of files) { - if (!file.endsWith('.json')) - continue - const stat = statSync(file) - if (stat.isFile()) { - rmSync(join(deleteDirName, file)) - } - } - } - else if (fileName.endsWith('.json')) { - rmSync(join(deleteDirName, fileName)) - } + for (const filePath of getTraceFilesToDelete(deleteDirName, fileName)) + rmSync(filePath) } diff --git a/src/traceFileDeletion.ts b/src/traceFileDeletion.ts new file mode 100644 index 0000000..715171c --- /dev/null +++ b/src/traceFileDeletion.ts @@ -0,0 +1,15 @@ +import { readdirSync, statSync } from 'node:fs' +import { join } from 'node:path' + +export function getTraceFilesToDelete(dirName: string, fileName: string): string[] { + if (fileName === '*') { + return readdirSync(dirName) + .map(file => join(dirName, file)) + .filter(filePath => statSync(filePath).isFile() && filePath.endsWith('.json')) + } + + if (fileName.endsWith('.json')) + return [join(dirName, fileName)] + + return [] +} diff --git a/test/trace-file-deletion.test.ts b/test/trace-file-deletion.test.ts new file mode 100644 index 0000000..e65134f --- /dev/null +++ b/test/trace-file-deletion.test.ts @@ -0,0 +1,52 @@ +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, describe, expect, it } from 'vitest' +import { getTraceFilesToDelete } from '../src/traceFileDeletion' + +const tempRoots: string[] = [] + +afterEach(() => { + while (tempRoots.length) { + const root = tempRoots.pop() + if (root) + rmSync(root, { recursive: true, force: true }) + } +}) + +describe('getTraceFilesToDelete', () => { + it('returns absolute json files in the target directory', () => { + const root = mkdtempSync(join(tmpdir(), 'tsperf-tracer-delete-')) + tempRoots.push(root) + + const traceDir = join(root, 'traces') + mkdirSync(traceDir, { recursive: true }) + + const jsonFile = join(traceDir, 'trace.json') + const txtFile = join(traceDir, 'notes.txt') + const nestedDir = join(traceDir, 'nested') + mkdirSync(nestedDir) + const nestedJson = join(nestedDir, 'nested.json') + + writeFileSync(jsonFile, '{}') + writeFileSync(txtFile, 'keep') + writeFileSync(nestedJson, '{}') + + expect(getTraceFilesToDelete(traceDir, '*')).toEqual([jsonFile]) + expect(readFileSync(jsonFile, 'utf8')).toBe('{}') + expect(readFileSync(txtFile, 'utf8')).toBe('keep') + expect(readFileSync(nestedJson, 'utf8')).toBe('{}') + }) + + it('returns a single absolute json path for direct deletion', () => { + const root = mkdtempSync(join(tmpdir(), 'tsperf-tracer-delete-one-')) + tempRoots.push(root) + + const traceDir = join(root, 'traces') + mkdirSync(traceDir, { recursive: true }) + const jsonFile = join(traceDir, 'trace.json') + writeFileSync(jsonFile, '{}') + + expect(getTraceFilesToDelete(traceDir, 'trace.json')).toEqual([jsonFile]) + }) +})