diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index 4fd8c38..0000000 --- a/src/constants.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * The number of milliseconds in an hour, used as a cache age. - */ -export const ONE_HOUR = 60 * 60 * 1000; diff --git a/src/repository-filesystem.test.ts b/src/repository-filesystem.test.ts deleted file mode 100644 index 2f490ae..0000000 --- a/src/repository-filesystem.test.ts +++ /dev/null @@ -1,233 +0,0 @@ -import * as utils from '@metamask/utils/node'; -import { - ensureDirectoryStructureExists, - writeFile, -} from '@metamask/utils/node'; -import fs from 'fs'; -import { mock } from 'jest-mock-extended'; -import path from 'path'; - -import { RepositoryFilesystem } from './repository-filesystem'; -import { withinSandbox } from '../tests/helpers'; - -jest.mock('@metamask/utils/node', () => { - return { - // eslint-disable-next-line @typescript-eslint/naming-convention - __esModule: true, - ...jest.requireActual('@metamask/utils/node'), - }; -}); - -const utilsMock = jest.mocked(utils); - -describe('RepositoryFilesystem', () => { - describe('readFile', () => { - describe('if the file has not already been read', () => { - it('reads the file from the repository directory', async () => { - jest.spyOn(utilsMock, 'readFile').mockResolvedValue('some content'); - const repositoryFilesystem = new RepositoryFilesystem( - '/some/directory', - ); - - await repositoryFilesystem.readFile('some.file'); - - expect(utilsMock.readFile).toHaveBeenCalledWith( - '/some/directory/some.file', - ); - }); - - it('returns the content of the file, with extra whitespace trimmed', async () => { - await withinSandbox(async ({ directoryPath: sandboxDirectoryPath }) => { - await writeFile( - path.join(sandboxDirectoryPath, 'some.file'), - ' some content ', - ); - const repositoryFilesystem = new RepositoryFilesystem( - sandboxDirectoryPath, - ); - - const content = await repositoryFilesystem.readFile('some.file'); - - expect(content).toBe('some content'); - }); - }); - }); - - describe('if the file has already been read', () => { - it('does not read the file from the repository directory again', async () => { - jest.spyOn(utilsMock, 'readFile').mockResolvedValue('some content'); - const repositoryFilesystem = new RepositoryFilesystem( - '/some/directory', - ); - await repositoryFilesystem.readFile('/some/file'); - - await repositoryFilesystem.readFile('/some/file'); - - expect(utilsMock.readFile).toHaveBeenCalledTimes(1); - }); - - it('returns the content of the file, with extra whitespace trimmed', async () => { - await withinSandbox(async ({ directoryPath: sandboxDirectoryPath }) => { - await writeFile( - path.join(sandboxDirectoryPath, 'some.file'), - ' some content ', - ); - const repositoryFilesystem = new RepositoryFilesystem( - sandboxDirectoryPath, - ); - await repositoryFilesystem.readFile('some.file'); - - const content = await repositoryFilesystem.readFile('some.file'); - - expect(content).toBe('some content'); - }); - }); - }); - }); - - describe('getEntryStats', () => { - describe('given a file', () => { - describe('if stats have not been requested for the file already', () => { - it('requests the stats for the file', async () => { - jest.spyOn(fs.promises, 'stat').mockResolvedValue(mock()); - const repositoryFilesystem = new RepositoryFilesystem( - '/some/directory', - ); - - await repositoryFilesystem.getEntryStats('some-entry'); - - expect(fs.promises.stat).toHaveBeenCalledWith( - '/some/directory/some-entry', - ); - }); - - it('returns stats for the file', async () => { - await withinSandbox( - async ({ directoryPath: sandboxDirectoryPath }) => { - await writeFile(path.join(sandboxDirectoryPath, 'some.file'), ''); - const repositoryFilesystem = new RepositoryFilesystem( - sandboxDirectoryPath, - ); - - const stats = await repositoryFilesystem.getEntryStats( - 'some.file', - ); - - expect(stats).toHaveProperty('atime'); - expect(stats).toHaveProperty('ctime'); - expect(stats).toHaveProperty('mtime'); - }, - ); - }); - }); - - describe('if stats have been requested for the file already', () => { - it('does not request the stats for the file again', async () => { - jest.spyOn(fs.promises, 'stat').mockResolvedValue(mock()); - const repositoryFilesystem = new RepositoryFilesystem( - '/some/directory', - ); - await repositoryFilesystem.getEntryStats('some-entry'); - - await repositoryFilesystem.getEntryStats('some-entry'); - - expect(fs.promises.stat).toHaveBeenCalledTimes(1); - }); - - it('returns stats for the file', async () => { - await withinSandbox( - async ({ directoryPath: sandboxDirectoryPath }) => { - await writeFile(path.join(sandboxDirectoryPath, 'some.file'), ''); - const repositoryFilesystem = new RepositoryFilesystem( - sandboxDirectoryPath, - ); - await repositoryFilesystem.getEntryStats('some.file'); - - const stats = await repositoryFilesystem.getEntryStats( - 'some.file', - ); - - expect(stats).toHaveProperty('atime'); - expect(stats).toHaveProperty('ctime'); - expect(stats).toHaveProperty('mtime'); - }, - ); - }); - }); - }); - - describe('given a directory', () => { - describe('if stats have not been requested for the directory already', () => { - it('requests the stats for the directory', async () => { - jest.spyOn(fs.promises, 'stat').mockResolvedValue(mock()); - const repositoryFilesystem = new RepositoryFilesystem( - '/some/directory', - ); - - await repositoryFilesystem.getEntryStats('/another/directory'); - - expect(fs.promises.stat).toHaveBeenCalledWith( - '/some/directory/another/directory', - ); - }); - - it('returns stats for the directory', async () => { - await withinSandbox( - async ({ directoryPath: sandboxDirectoryPath }) => { - await ensureDirectoryStructureExists( - path.join(sandboxDirectoryPath, 'some-directory'), - ); - const repositoryFilesystem = new RepositoryFilesystem( - sandboxDirectoryPath, - ); - - const stats = await repositoryFilesystem.getEntryStats( - 'some-directory', - ); - - expect(stats).toHaveProperty('atime'); - expect(stats).toHaveProperty('ctime'); - expect(stats).toHaveProperty('mtime'); - }, - ); - }); - }); - - describe('if stats have been requested for the directory already', () => { - it('does not request the stats for the directory again', async () => { - jest.spyOn(fs.promises, 'stat').mockResolvedValue(mock()); - const repositoryFilesystem = new RepositoryFilesystem( - '/some/directory', - ); - await repositoryFilesystem.getEntryStats('another-directory'); - - await repositoryFilesystem.getEntryStats('another-directory'); - - expect(fs.promises.stat).toHaveBeenCalledTimes(1); - }); - - it('returns stats for the directory', async () => { - await withinSandbox( - async ({ directoryPath: sandboxDirectoryPath }) => { - await ensureDirectoryStructureExists( - path.join(sandboxDirectoryPath, 'some-directory'), - ); - const repositoryFilesystem = new RepositoryFilesystem( - sandboxDirectoryPath, - ); - await repositoryFilesystem.getEntryStats('some-directory'); - - const stats = await repositoryFilesystem.getEntryStats( - 'some-directory', - ); - - expect(stats).toHaveProperty('atime'); - expect(stats).toHaveProperty('ctime'); - expect(stats).toHaveProperty('mtime'); - }, - ); - }); - }); - }); - }); -}); diff --git a/src/repository-filesystem.ts b/src/repository-filesystem.ts deleted file mode 100644 index e13ca7b..0000000 --- a/src/repository-filesystem.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { readFile } from '@metamask/utils/node'; -import type fs from 'fs'; -import path from 'path'; - -import { getEntryStats } from './misc-utils'; - -/** - * Used to access files within either a project (the repository being linted) or - * a template (the repository that the project is compared to). Any filesystem - * operation performed is cached to make rule execution for the same project or - * template as fast as possible. - */ -export class RepositoryFilesystem { - #directoryPath: string; - - #fileContents: Record; - - #entryStats: Record; - - /** - * Constructs a RepositoryFilesystem. - * - * @param directoryPath - The path to the repository. - */ - constructor(directoryPath: string) { - this.#directoryPath = directoryPath; - this.#fileContents = {}; - this.#entryStats = {}; - } - - /** - * Reads a file within the repository. - * - * @param filePath - The path to the file within the context of the repository - * (so, minus its directory). - * @returns The contents of the file. - */ - async readFile(filePath: string): Promise { - const cachedContent = this.#fileContents[filePath]; - const content = - cachedContent ?? (await readFile(this.#getFullPath(filePath))).trim(); - this.#fileContents[filePath] = content; - return content; - } - - /** - * Retrieves stats for the given file or directory. - * - * @param entryPath - The path to the file or directory within the context of - * the repository (so, minus its directory). - * @returns The `fs.Stats` object with information about the entry. - */ - async getEntryStats(entryPath: string): Promise { - const cachedStats = this.#entryStats[entryPath]; - const stats = - cachedStats ?? (await getEntryStats(this.#getFullPath(entryPath))); - this.#entryStats[entryPath] = stats; - return stats; - } - - /** - * Builds the full path to a file or directory within the repository from a - * partial path. - * - * @param entryPath - The path to the file or directory within the context of - * the repository (so, minus its directory). - * @returns The full path. - */ - #getFullPath(entryPath: string): string { - return path.join(this.#directoryPath, entryPath); - } -}