Skip to content

finances: add rogers and refactor#14

Merged
denversc merged 14 commits into
mainfrom
rogers
Jun 19, 2026
Merged

finances: add rogers and refactor#14
denversc merged 14 commits into
mainfrom
rogers

Conversation

@denversc

Copy link
Copy Markdown
Owner

No description provided.

@denversc
denversc merged commit 3ea6295 into main Jun 19, 2026
3 checks passed
@denversc
denversc deleted the rogers branch June 19, 2026 05:09

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +61 to +68
if (options?.v) {
console.log(`Renaming ${srcFilePath} to ${destFileName}`);
} else {
console.log(destFilePath);
}

await fs.rename(srcFilePath, destFilePath);
renamedPaths.add(srcFilePath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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);

Comment thread finances/index.ts
Comment on lines +2 to +6
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";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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";

Comment on lines +2 to +3
import { isDocumentParseError } from "./document.ts";
import { identify, isIdentifyError } from "./identify.ts";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Import 'Document' and 'ParsedDocument' types to enable a fully type-safe helper function for parsing and calculating file names, avoiding unsafe 'any' casts.

Suggested change
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";

Comment on lines +65 to +76
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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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);

Comment on lines +97 to +100
const numberByHash = new Map<string, number>();
for (const hash of hashes) {
numberByHash.set(hash, numberByHash.size + 1);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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);
}

Comment on lines +131 to +132
return fileNameByFilePath;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Define the generic helper function 'parseAndCalculate' to safely handle the parsing and file name calculation without losing type safety.

Suggested change
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);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant