Skip to content
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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

enzonotario
Copy link
Owner

Description

Related issues/external references

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation improvement
  • Style (Change that do not affect the functionality of the code)
  • CI/CD (Changes to the CI/CD configuration)

Copy link

vercel bot commented Oct 17, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
vitepress-openapi ✅ Ready (Inspect) Visit Preview 💬 Add feedback Oct 17, 2024 2:41am

Copy link
Contributor

coderabbitai bot commented Oct 17, 2024

Walkthrough

The changes in this pull request involve modifications to the formatJson function located in src/lib/formatJson.ts. The function has been updated to enhance its handling of circular references in JSON objects by introducing a custom replacer function obtained from getCircularReplacer(). This function tracks object references during serialization and replaces circular references with the string '[Circular]'. The overall structure of the function remains unchanged, including the existing try-catch block for error handling.

Changes

File Change Summary
src/lib/formatJson.ts Updated formatJson function to handle circular references using a custom replacer function from getCircularReplacer(). Added getCircularReplacer() function.

Possibly related PRs

  • fix(openapi parser): handle exceptions gracefully #79: This PR modifies the OpenApi function in src/lib/OpenApi.ts, which is related to the formatJson function's handling of JSON serialization, as both involve JSON processing and error handling.
  • examples && re-use parsedSpec #88: This PR updates the OpenApi function in src/lib/OpenApi.ts, adding a new parameter parsedSpec, which relates to the overall handling of JSON specifications, similar to the enhancements made in the formatJson function for circular references.

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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

pkg-pr-new bot commented Oct 17, 2024

Open in Stackblitz

pnpm add https://pkg.pr.new/vitepress-openapi@95
pnpm add https://pkg.pr.new/vitepress-openapi@95

commit: 16d0e3c

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 formatJson

Length 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.ts

Length of output: 1630

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 5c71dc9 and 967a6ed.

📒 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 named seen 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.

Comment on lines 9 to 17
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)
Copy link
Contributor

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.

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📥 Commits

Files that changed from the base of the PR and between 967a6ed and bec5cee.

📒 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 in formatJson, provides a robust solution that aligns well with the PR objectives.

Key improvements:

  1. Circular references are now detected and replaced with '[Circular]'.
  2. The solution maintains the existing error handling and null/undefined checks.
  3. 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.

@@ -4,8 +4,26 @@ export function formatJson(json: any): string {
}

try {
return JSON.stringify(json ?? {}, null, 2)
return JSON.stringify(json ?? {}, getCircularReplacer(), 2)
Copy link
Contributor

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.

Suggested change
return JSON.stringify(json ?? {}, getCircularReplacer(), 2)
// Use custom replacer to handle circular references
return JSON.stringify(json ?? {}, getCircularReplacer(), 2)

Comment on lines 13 to 29
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
}
}
Copy link
Contributor

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.

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

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