Files
privacy.sexy/src/infrastructure/ReadbackFileWriter/NodeReadbackFileWriter.ts
undergroundwires a721e82a4f Bump TypeScript to 5.3 with verbatimModuleSyntax
This commit upgrades TypeScript to the latest version 5.3 and introduces
`verbatimModuleSyntax` in line with the official Vue guide
recommendatinos (vuejs/docs#2592).

By enforcing `import type` for type-only imports, this commit improves
code clarity and supports tooling optimization, ensuring imports are
only bundled when necessary for runtime.

Changes:

- Bump TypeScript to 5.3.3 across the project.
- Adjust import statements to utilize `import type` where applicable,
  promoting cleaner and more efficient code.
2024-02-27 04:20:22 +01:00

116 lines
3.9 KiB
TypeScript

import { writeFile, access, readFile } from 'node:fs/promises';
import { constants } from 'node:fs';
import type { Logger } from '@/application/Common/Log/Logger';
import { ElectronLogger } from '../Log/ElectronLogger';
import type {
FailedFileWrite, ReadbackFileWriter, FileWriteErrorType,
FileWriteOutcome, SuccessfulFileWrite,
} from './ReadbackFileWriter';
const FILE_ENCODING: NodeJS.BufferEncoding = 'utf-8';
export class NodeReadbackFileWriter implements ReadbackFileWriter {
constructor(
private readonly logger: Logger = ElectronLogger,
private readonly fileSystem: FileReadWriteOperations = {
writeFile,
readFile: (path, encoding) => readFile(path, encoding),
access,
},
) { }
public async writeAndVerifyFile(
filePath: string,
fileContents: string,
): Promise<FileWriteOutcome> {
this.logger.info(`Starting file write and verification process for: ${filePath}`);
const fileWritePipelineActions: ReadonlyArray<() => Promise<FileWriteOutcome>> = [
() => this.createOrOverwriteFile(filePath, fileContents),
() => this.verifyFileExistsWithoutReading(filePath),
() => this.verifyFileContentsByReading(filePath, fileContents),
];
for (const action of fileWritePipelineActions) {
const actionOutcome = await action(); // eslint-disable-line no-await-in-loop
if (!actionOutcome.success) {
return actionOutcome;
}
}
return this.reportSuccess(`File successfully written and verified: ${filePath}`);
}
private async createOrOverwriteFile(
filePath: string,
fileContents: string,
): Promise<FileWriteOutcome> {
try {
this.logger.info(`Creating file at ${filePath}, size: ${fileContents.length} characters`);
await this.fileSystem.writeFile(filePath, fileContents, FILE_ENCODING);
return this.reportSuccess('Created file.');
} catch (error) {
return this.reportFailure('WriteOperationFailed', error);
}
}
private async verifyFileExistsWithoutReading(
filePath: string,
): Promise<FileWriteOutcome> {
try {
await this.fileSystem.access(filePath, constants.F_OK);
return this.reportSuccess('Verified file existence without reading.');
} catch (error) {
return this.reportFailure('FileExistenceVerificationFailed', error);
}
}
private async verifyFileContentsByReading(
filePath: string,
expectedFileContents: string,
): Promise<FileWriteOutcome> {
try {
const actualFileContents = await this.fileSystem.readFile(filePath, FILE_ENCODING);
if (actualFileContents !== expectedFileContents) {
return this.reportFailure(
'ContentVerificationFailed',
[
'The contents of the written file do not match the expected contents.',
'Written file contents do not match the expected file contents',
`File path: ${filePath}`,
`Expected total characters: ${actualFileContents.length}`,
`Actual total characters: ${expectedFileContents.length}`,
].join('\n'),
);
}
return this.reportSuccess('Verified file content by reading.');
} catch (error) {
return this.reportFailure('ReadVerificationFailed', error);
}
}
private reportFailure(
errorType: FileWriteErrorType,
error: Error | string,
): FailedFileWrite {
this.logger.error('Error saving file', errorType, error);
return {
success: false,
error: {
type: errorType,
message: typeof error === 'string' ? error : error.message,
},
};
}
private reportSuccess(successAction: string): SuccessfulFileWrite {
this.logger.info(`Successful file save: ${successAction}`);
return {
success: true,
};
}
}
export interface FileReadWriteOperations {
readonly writeFile: typeof writeFile;
readonly access: typeof access;
readFile: (filePath: string, encoding: NodeJS.BufferEncoding) => Promise<string>;
}