-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Restore PR #5332 - 2 #8168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Restore PR #5332 - 2 #8168
Conversation
Implement safeReadJson function to complement the existing safeWriteJson functionality: - Uses stream-json for efficient processing of large JSON files - Supports both full object reading and selective path extraction - Provides file locking to prevent concurrent access - Includes comprehensive error handling - Adds complete test coverage - Passthrough all exceptions This enables efficient and safe JSON reading operations throughout the codebase. Signed-off-by: Eric Wheeler <[email protected]>
Replace manual file reading and JSON parsing with the safer safeReadJson utility across multiple files in the codebase. This change: - Provides atomic file access with proper locking to prevent race conditions - Streams file contents efficiently for better memory usage - Improves error handling consistency - Reduces code duplication Fixes: #5331 Signed-off-by: Eric Wheeler <[email protected]>
Updated test files to properly mock and use safeReadJson/safeWriteJson: - Added proper imports for safeReadJson from safeWriteJson module - Updated mock implementations to mock both functions correctly - Replaced direct fs operations with calls to safe functions - Updated assertions to match the new behavior This fixes all failing tests after the conversion to safeReadJson. Signed-off-by: Eric Wheeler <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR restores the implementation of safeReadJson utility and integrates it throughout the codebase to provide atomic, streaming JSON file reading with proper locking. The changes replace manual fs.readFile + JSON.parse patterns with a unified, safer approach.
- Implements
safeReadJsonfunction with streaming JSON parsing and file locking - Refactors all JSON file reading operations to use the new safe utility
- Updates tests to mock the new utility instead of direct file system operations
Reviewed Changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/safeReadJson.ts | New safe JSON reading utility with streaming and locking |
| src/utils/safeWriteJson.ts | Extracts lock acquisition to shared function |
| src/utils/tests/safeReadJson.spec.ts | Comprehensive test suite for the new utility |
| Multiple service files | Replace manual JSON reading with safeReadJson |
| Multiple test files | Update mocks to use new utility |
| .roo/rules/use-safeReadJson.md | Documentation for the new pattern |
Comments suppressed due to low confidence (1)
src/services/mdm/tests/MdmService.spec.ts:1
- The property access
error.codeshould be properly typed. The error parameter should be cast to the appropriate type or checked withhasOwnPropertybefore accessing thecodeproperty.
import * as path from "path"
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| `[Roo-Debug] readApiMessages: Error reading OLD API conversation history file (claude_messages.json). TaskId: ${taskId}, Path: ${oldPath}, Error: ${oldError}`, | ||
| ) | ||
| // DO NOT unlink oldPath if parsing failed, throw error instead. | ||
| throw error | ||
| throw oldError | ||
| } | ||
| } else { | ||
| // For any other error with the main file, log and rethrow | ||
| console.error( | ||
| `[Roo-Debug] readApiMessages: Error reading API conversation history file. TaskId: ${taskId}, Path: ${filePath}, Error: ${error}`, |
Copilot
AI
Sep 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message should include the actual error message from the caught error rather than just ${error}, which may not provide meaningful information. Consider using error.message or similar.
| // For any other error with the old file, log and rethrow | ||
| console.error( | ||
| `[Roo-Debug] readApiMessages: Error parsing OLD API conversation history file (claude_messages.json). TaskId: ${taskId}, Path: ${oldPath}, Error: ${error}`, | ||
| `[Roo-Debug] readApiMessages: Error reading OLD API conversation history file (claude_messages.json). TaskId: ${taskId}, Path: ${oldPath}, Error: ${oldError}`, |
Copilot
AI
Sep 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message should include the actual error message from the caught error rather than just ${oldError}, which may not provide meaningful information. Consider using oldError.message or similar.
| `[Roo-Debug] readApiMessages: Error reading OLD API conversation history file (claude_messages.json). TaskId: ${taskId}, Path: ${oldPath}, Error: ${oldError}`, | |
| `[Roo-Debug] readApiMessages: Error reading OLD API conversation history file (claude_messages.json). TaskId: ${taskId}, Path: ${oldPath}, Error: ${oldError.message}`, |
| apiConversationHistory, | ||
| } | ||
| } catch (error) { | ||
| if (error.code !== "ENOENT") { |
Copilot
AI
Sep 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The property access error.code should be properly typed. The error parameter should be cast to the appropriate type (e.g., error as any or error as NodeJS.ErrnoException) before accessing the code property.
| if (error.code !== "ENOENT") { | |
| if ((error as NodeJS.ErrnoException).code !== "ENOENT") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your contribution! I've reviewed the changes and found several issues that need attention. The implementation of safeReadJson is well-structured with proper streaming and locking, but there are some type safety and consistency concerns that should be addressed.
| } catch (error) { | ||
| this.log(`[MDM] Error reading MDM config from ${configPath}:`, error) | ||
| // If file doesn't exist, return null | ||
| if ((error as any)?.code !== "ENOENT") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type safety issue: Using (error as any)?.code defeats TypeScript's type safety. Consider using a proper type guard instead:
| if ((error as any)?.code !== "ENOENT") { | |
| if (error && typeof error === 'object' && 'code' in error && (error as NodeJS.ErrnoException).code !== "ENOENT") { |
This ensures type safety while checking for the ENOENT error code.
| @@ -0,0 +1,33 @@ | |||
| # JSON File Reading Must Be Safe and Atomic | |||
|
|
|||
| - You MUST use `safeReadJson(filePath: string, jsonPath?: string | string[]): Promise<any>` from `src/utils/safeReadJson.ts` to read JSON files | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation mismatch: The function signature mentions jsonPath?: string | string[] parameter, but the actual implementation in safeReadJson.ts doesn't have this parameter. Could you update the documentation to match the implementation?
| return exists ? JSON.parse(await fs.readFile(filePath, "utf8")) : undefined | ||
| try { | ||
| return await safeReadJson(filePath) | ||
| } catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this intentional? The error is silently caught and returns undefined without any logging. Consider at least logging the error for debugging purposes, or add a comment explaining why all errors should be silently ignored here.
| import * as fsSync from "fs" | ||
| import * as path from "path" | ||
| import * as Parser from "stream-json/Parser" | ||
| import * as Pick from "stream-json/filters/Pick" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import: The Pick import from 'stream-json/filters/Pick' is not used anywhere in this file. Could we remove it?
| const content = await fs.readFile(configPath, "utf-8") | ||
| const config = JSON.parse(content) | ||
| // This is a read-modify-write-operation, but we cannot | ||
| // use safeWriteJson because it does not (yet) support pretty printing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technical debt indicator: Multiple comments mention "cannot use safeWriteJson because it does not (yet) support pretty printing". Should we create an issue to track adding pretty printing support to safeWriteJson? This would eliminate these workarounds.
| } | ||
|
|
||
| // Success Scenarios | ||
| test("should successfully read a JSON file", async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good test coverage! Consider adding a test for concurrent read scenarios to verify that the locking mechanism properly handles multiple simultaneous reads of the same file. This would ensure the atomic read guarantee is working as expected.
Important
Introduce
safeReadJsonfor safe JSON file reading and update codebase to use it, enhancing file access safety and performance.safeReadJsoninsafeReadJson.tsfor atomic and safe JSON file reading using streaming and locking.safeReadJsoninmodelCache.ts,modelEndpointCache.ts,importExport.ts,FileContextTracker.ts,apiMessages.ts,taskMessages.ts,ClineProvider.ts,extract-text.ts,MarketplaceManager.ts,SimpleInstaller.ts,McpHub.ts,MdmService.ts, andautoImportSettings.spec.ts.safeReadJson.spec.tsto testsafeReadJsonfunctionality.SimpleInstaller.spec.ts,McpHub.spec.ts,MdmService.spec.ts, andautoImportSettings.spec.tsto mocksafeReadJson..roo/rules/use-safeReadJson.mdto enforce the use ofsafeReadJsonfor JSON file reading.This description was created by
for 47c0856. You can customize this summary. It will automatically update as commits are pushed.