-
Notifications
You must be signed in to change notification settings - Fork 8
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
fix(formatJson): handle circular reference #95
base: main
Are you sure you want to change the base?
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThe changes in this pull request involve modifications to the Changes
Possibly related PRs
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
commit: |
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.
Actionable comments posted: 1
🧹 Outside diff range comments (1)
src/lib/formatJson.ts (1)
Missing test case for circular references.
The test file
test/lib/formatJson.test.ts
does not include the suggested test case for handling circular references. Please add the following test case to ensure proper functionality:it('should handle circular references', () => { const circularObj: any = { a: 1 }; circularObj.self = circularObj; const result = formatJson(circularObj); expect(result).toContain('"self": "[Circular Reference]"'); });🔗 Analysis chain
Line range hint
1-21
: Robust circular reference handling with maintained backwards compatibility.The changes effectively address the issue of circular references in JSON objects while maintaining the function's original signature and error handling. This implementation provides more robust JSON formatting capabilities without introducing breaking changes.
To ensure the new functionality works as expected, consider adding a test case with a circular reference:
it('should handle circular references', () => { const circularObj: any = { a: 1 }; circularObj.self = circularObj; const result = formatJson(circularObj); expect(result).toContain('"self": "[Circular Reference]"'); });To verify the existence of test files, run:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for the presence of test files related to formatJson # Test: Search for test files. Expect: At least one test file related to formatJson. fd -e test.ts -e spec.ts formatJsonLength of output: 65
Script:
#!/bin/bash # Description: Retrieve the contents of formatJson.test.ts to verify the existence of the circular reference test case. cat test/lib/formatJson.test.tsLength of output: 1630
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
📒 Files selected for processing (1)
- src/lib/formatJson.ts (1 hunks)
🧰 Additional context used
🔇 Additional comments (1)
src/lib/formatJson.ts (1)
6-7
: Good choice using WeakSet for circular reference detection.The introduction of a
WeakSet
namedseen
is an excellent approach for tracking objects during JSON serialization. This data structure allows for efficient object tracking without preventing garbage collection, which is crucial for memory management.
src/lib/formatJson.ts
Outdated
return JSON.stringify(json ?? {}, (key, value) => { | ||
if (typeof value === 'object' && value !== null) { | ||
if (seen.has(value)) { | ||
return '[Circular Reference]' | ||
} | ||
seen.add(value) | ||
} | ||
return value | ||
}, 2) |
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.
🧹 Nitpick (assertive)
Effective implementation of circular reference handling.
The custom replacer function successfully detects and handles circular references in the JSON structure. It correctly identifies object types, checks for previously seen objects, and adds new objects to the seen
set.
A minor optimization could be made by combining the null check with the typeof check:
Consider refactoring the condition to:
- if (typeof value === 'object' && value !== null) {
+ if (value && typeof value === 'object') {
This slight change maintains the same logic but reduces the number of checks performed.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
return JSON.stringify(json ?? {}, (key, value) => { | |
if (typeof value === 'object' && value !== null) { | |
if (seen.has(value)) { | |
return '[Circular Reference]' | |
} | |
seen.add(value) | |
} | |
return value | |
}, 2) | |
return JSON.stringify(json ?? {}, (key, value) => { | |
if (value && typeof value === 'object') { | |
if (seen.has(value)) { | |
return '[Circular Reference]' | |
} | |
seen.add(value) | |
} | |
return value | |
}, 2) |
967a6ed
to
bec5cee
Compare
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.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
📒 Files selected for processing (1)
- src/lib/formatJson.ts (1 hunks)
🧰 Additional context used
🔇 Additional comments (1)
src/lib/formatJson.ts (1)
Line range hint
1-29
: Summary: Effective solution for handling circular references in JSON formatting.The changes implemented in this file successfully address the issue of circular references in JSON objects. The new
getCircularReplacer
function, combined with its usage informatJson
, provides a robust solution that aligns well with the PR objectives.Key improvements:
- Circular references are now detected and replaced with '[Circular]'.
- The solution maintains the existing error handling and null/undefined checks.
- The implementation is efficient and follows good coding practices.
These changes significantly enhance the reliability of the JSON formatting process without introducing breaking changes to the existing API.
src/lib/formatJson.ts
Outdated
@@ -4,8 +4,26 @@ export function formatJson(json: any): string { | |||
} | |||
|
|||
try { | |||
return JSON.stringify(json ?? {}, null, 2) | |||
return JSON.stringify(json ?? {}, getCircularReplacer(), 2) |
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.
🧹 Nitpick (assertive)
Excellent implementation of circular reference handling.
The use of getCircularReplacer()
effectively addresses the issue of circular references in JSON objects. This change aligns well with the PR objectives and provides a robust solution to the problem.
For improved clarity, consider adding a brief comment explaining the purpose of getCircularReplacer()
:
- return JSON.stringify(json ?? {}, getCircularReplacer(), 2)
+ // Use custom replacer to handle circular references
+ return JSON.stringify(json ?? {}, getCircularReplacer(), 2)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
return JSON.stringify(json ?? {}, getCircularReplacer(), 2) | |
// Use custom replacer to handle circular references | |
return JSON.stringify(json ?? {}, getCircularReplacer(), 2) |
src/lib/formatJson.ts
Outdated
function getCircularReplacer() { | ||
const ancestors = [] | ||
return function (key, value) { | ||
if (typeof value !== 'object' || value === null) { | ||
return value | ||
} | ||
// `this` is the object that value is contained in, i.e., its direct parent. | ||
while (ancestors.length > 0 && ancestors.at(-1) !== this) { | ||
ancestors.pop() | ||
} | ||
if (ancestors.includes(value)) { | ||
return '[Circular]' | ||
} | ||
ancestors.push(value) | ||
return value | ||
} | ||
} |
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.
🧹 Nitpick (assertive)
Well-implemented circular reference detection.
The getCircularReplacer
function effectively detects and handles circular references in the JSON structure. It correctly identifies object types, checks for previously seen objects, and adds new objects to the ancestors
array.
Consider implementing the minor optimization suggested in the past review:
- if (typeof value !== 'object' || value === null) {
+ if (!value || typeof value !== 'object') {
This change maintains the same logic but reduces the number of checks performed, potentially improving performance slightly.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
function getCircularReplacer() { | |
const ancestors = [] | |
return function (key, value) { | |
if (typeof value !== 'object' || value === null) { | |
return value | |
} | |
// `this` is the object that value is contained in, i.e., its direct parent. | |
while (ancestors.length > 0 && ancestors.at(-1) !== this) { | |
ancestors.pop() | |
} | |
if (ancestors.includes(value)) { | |
return '[Circular]' | |
} | |
ancestors.push(value) | |
return value | |
} | |
} | |
function getCircularReplacer() { | |
const ancestors = [] | |
return function (key, value) { | |
if (!value || typeof value !== 'object') { | |
return value | |
} | |
// `this` is the object that value is contained in, i.e., its direct parent. | |
while (ancestors.length > 0 && ancestors.at(-1) !== this) { | |
ancestors.pop() | |
} | |
if (ancestors.includes(value)) { | |
return '[Circular]' | |
} | |
ancestors.push(value) | |
return value | |
} | |
} |
bec5cee
to
fc1251e
Compare
fc1251e
to
f377079
Compare
f377079
to
821bcfa
Compare
821bcfa
to
16d0e3c
Compare
Description
Related issues/external references
Types of changes