Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the financial PDF parsing script by modularizing it into separate files for commands, document types, and utility functions. Feedback focuses on improving safety and type safety, including checking for existing files before renaming, sorting hashes for deterministic file numbering, adding missing '.ts' extensions to imports, and introducing a generic helper function to eliminate unsafe 'any' casts.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if (options?.v) { | ||
| console.log(`Renaming ${srcFilePath} to ${destFileName}`); | ||
| } else { | ||
| console.log(destFilePath); | ||
| } | ||
|
|
||
| await fs.rename(srcFilePath, destFilePath); | ||
| renamedPaths.add(srcFilePath); |
There was a problem hiding this comment.
To prevent accidental data loss, check if the destination file already exists before renaming. 'fs.rename' will silently overwrite the target file if it exists, which can lead to lost files if multiple source files map to the same name or if a file with that name was already present.
let destExists = false;
try {
await fs.access(destFilePath);
destExists = true;
} catch {
// Destination does not exist, safe to rename
}
if (destExists) {
console.error(
"ERROR: Destination file already exists, skipping to prevent overwrite: " + destFilePath,
);
skippedCount++;
continue;
}
if (options?.v) {
console.log("Renaming " + srcFilePath + " to " + destFileName);
} else {
console.log(destFilePath);
}
await fs.rename(srcFilePath, destFilePath);
renamedPaths.add(srcFilePath);| import { printCommand } from "./commands/print"; | ||
| import { identifyCommand } from "./commands/identify"; | ||
| import { parseCommand } from "./commands/parse"; | ||
| import { filenameCommand } from "./commands/filename"; | ||
| import { renameCommand } from "./commands/rename"; |
There was a problem hiding this comment.
For consistency with the rest of the codebase (which uses explicit '.ts' extensions for all local imports), please add the '.ts' extension to these imports. This also ensures compatibility with environments that strictly require file extensions.
| import { printCommand } from "./commands/print"; | |
| import { identifyCommand } from "./commands/identify"; | |
| import { parseCommand } from "./commands/parse"; | |
| import { filenameCommand } from "./commands/filename"; | |
| import { renameCommand } from "./commands/rename"; | |
| import { printCommand } from "./commands/print.ts"; | |
| import { identifyCommand } from "./commands/identify.ts"; | |
| import { parseCommand } from "./commands/parse.ts"; | |
| import { filenameCommand } from "./commands/filename.ts"; | |
| import { renameCommand } from "./commands/rename.ts"; |
| import { isDocumentParseError } from "./document.ts"; | ||
| import { identify, isIdentifyError } from "./identify.ts"; |
There was a problem hiding this comment.
Import 'Document' and 'ParsedDocument' types to enable a fully type-safe helper function for parsing and calculating file names, avoiding unsafe 'any' casts.
| import { isDocumentParseError } from "./document.ts"; | |
| import { identify, isIdentifyError } from "./identify.ts"; | |
| import { type Document, isDocumentParseError, type ParsedDocument } from "./document.ts"; | |
| import { identify, isIdentifyError } from "./identify.ts"; |
| const parseResult = document.parse(readPdfResult.lines); | ||
| if (isDocumentParseError(parseResult)) { | ||
| return { | ||
| type: "CalculateFileNamesError", | ||
| message: parseResult.message, | ||
| filePath, | ||
| }; | ||
| } | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const fileName = document.calculateFileName(parseResult as unknown as any); | ||
| fileNameByFilePath.set(filePath, fileName); |
There was a problem hiding this comment.
Instead of using an unsafe 'as unknown as any' cast and disabling ESLint rules, we can use a generic helper function 'parseAndCalculate' to parse and calculate the file name in a 100% type-safe manner.
| const parseResult = document.parse(readPdfResult.lines); | |
| if (isDocumentParseError(parseResult)) { | |
| return { | |
| type: "CalculateFileNamesError", | |
| message: parseResult.message, | |
| filePath, | |
| }; | |
| } | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| const fileName = document.calculateFileName(parseResult as unknown as any); | |
| fileNameByFilePath.set(filePath, fileName); | |
| const fileName = parseAndCalculate(document, readPdfResult.lines); | |
| if (isDocumentParseError(fileName)) { | |
| return { | |
| type: "CalculateFileNamesError", | |
| message: fileName.message, | |
| filePath, | |
| }; | |
| } | |
| fileNameByFilePath.set(filePath, fileName); |
| const numberByHash = new Map<string, number>(); | ||
| for (const hash of hashes) { | ||
| numberByHash.set(hash, numberByHash.size + 1); | ||
| } |
There was a problem hiding this comment.
Sorting the hashes before assigning numbers ensures that the numbering is completely deterministic and independent of the order in which the files are passed to the command.
| const numberByHash = new Map<string, number>(); | |
| for (const hash of hashes) { | |
| numberByHash.set(hash, numberByHash.size + 1); | |
| } | |
| const numberByHash = new Map<string, number>(); | |
| const sortedHashes = Array.from(hashes).sort(); | |
| for (const hash of sortedHashes) { | |
| numberByHash.set(hash, numberByHash.size + 1); | |
| } |
| return fileNameByFilePath; | ||
| } |
There was a problem hiding this comment.
Define the generic helper function 'parseAndCalculate' to safely handle the parsing and file name calculation without losing type safety.
| return fileNameByFilePath; | |
| } | |
| return fileNameByFilePath; | |
| } | |
| function parseAndCalculate< | |
| ParsedDocumentT extends ParsedDocument<TypeName>, | |
| TypeName extends string, | |
| >( | |
| document: Document<ParsedDocumentT, TypeName>, | |
| lines: readonly string[], | |
| ): string | DocumentParseError { | |
| const parseResult = document.parse(lines); | |
| if (isDocumentParseError(parseResult)) { | |
| return parseResult; | |
| } | |
| return document.calculateFileName(parseResult); | |
| } |
No description provided.