Skip to content

feat: Add AST-based Code Complexity Profiler component - #1750

Open
desireddymohithreddy0925 wants to merge 1 commit into
Canopus-Labs:mainfrom
desireddymohithreddy0925:feat/ast-complexity-profiler
Open

feat: Add AST-based Code Complexity Profiler component#1750
desireddymohithreddy0925 wants to merge 1 commit into
Canopus-Labs:mainfrom
desireddymohithreddy0925:feat/ast-complexity-profiler

Conversation

@desireddymohithreddy0925

@desireddymohithreddy0925 desireddymohithreddy0925 commented Aug 10, 2026

Copy link
Copy Markdown

Description

This PR implements the Dynamic AST-based Code Complexity Profiler as proposed. It evaluates users' code submissions dynamically on the client side to estimate algorithmic time complexity (Big-O notation).

Changes Made

  • Created CodeComplexityProfiler.jsx in frontend/src/components/.
  • Integrated @babel/standalone to generate Abstract Syntax Trees (ASTs) in the browser.
  • Implemented custom AST traversal to detect loop depth (e.g., nested ForStatement and WhileStatement) to accurately predict O(n), O(n^2), etc.

Checklist

  • Code compiles without errors
  • Static AST analysis prevents server-side dynamic execution bottlenecks
  • Tested locally

Adds the CodeComplexityProfiler React component. The component parses JavaScript with @babel/standalone, detects nested for and while loops, estimates Big-O complexity, and displays analysis results. It also reports parsing errors.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a React component that parses supplied JavaScript with Babel, counts for and while loops, calculates maximum nesting, estimates Big-O complexity, and displays results or parse errors.

Changes

JavaScript complexity profiler

Layer / File(s) Summary
AST analysis and complexity estimation
frontend/src/components/CodeComplexityProfiler.jsx
The component parses JavaScript, traverses loop nodes, counts loops, calculates maximum nesting depth, estimates Big-O complexity, and logs parse errors.
Profiler results interface
frontend/src/components/CodeComplexityProfiler.jsx
The component renders the Analyze button, conditional error output, and conditional analysis results.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant CodeComplexityProfiler
  participant BabelParser
  participant BabelTraverse
  User->>CodeComplexityProfiler: Click Analyze
  CodeComplexityProfiler->>BabelParser: Parse supplied JavaScript
  BabelParser->>BabelTraverse: Traverse parsed AST
  BabelTraverse-->>CodeComplexityProfiler: Return loop counts and nesting depth
  CodeComplexityProfiler-->>User: Display estimated complexity
Loading

Possibly related issues

  • Issue 1745 — Requests an AST-based JavaScript complexity profiler that detects nested loops and estimates Big-O complexity.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the added AST-based Code Complexity Profiler component.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

Warning

⚠️ This pull request shows signs of AI-generated slop (redundant_comments, phantom_api). It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/components/CodeComplexityProfiler.jsx`:
- Around line 21-32: Extend the loop visitors in the Babel traversal used by the
complexity profiler to include ForInStatement, ForOfStatement, and
DoWhileStatement alongside ForStatement and WhileStatement. Ensure each new
visitor increments loopCount and updates maxDepth using the same ancestry-based
depth calculation.
- Around line 45-48: Update the parse-error catch block in
CodeComplexityProfiler to clear the existing complexity result before setting
the parse error, ensuring stale analysis metrics are not displayed after invalid
code is submitted.
- Around line 13-21: Add `@babel/standalone` to frontend/package.json and the
lockfile, then update CodeComplexityProfiler to parse and traverse through
babel.packages.parser.parse and babel.packages.traverse. Extend its traversal
visitors to count ForInStatement, ForOfStatement, and DoWhileStatement, and
clear the complexity state in the error path so stale results are not retained.
- Line 2: Declare `@babel/standalone` in frontend/package.json and synchronize
frontend/package-lock.json. In CodeComplexityProfiler, replace unsupported
top-level babel.parse and babel.traverse calls with the supported
babel.packages.parser and babel.packages.traverse APIs.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ef67fdba-5a9f-4f91-9944-5604e01ce107

📥 Commits

Reviewing files that changed from the base of the PR and between fd811d3 and bfa0254.

📒 Files selected for processing (1)
  • frontend/src/components/CodeComplexityProfiler.jsx

@@ -0,0 +1,89 @@
import React, { useState } from 'react';
import * as babel from '@babel/standalone';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

jq -e '
  (.dependencies // {})["`@babel/standalone`"] //
  (.devDependencies // {})["`@babel/standalone`"]
' frontend/package.json

Repository: Canopus-Labs/PrepPilot

Length of output: 165


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- manifests and lockfiles ---'
git ls-files '*package.json' '*package-lock.json' '*yarn.lock' '*pnpm-lock.yaml' '*npm-shrinkwrap.json'

printf '%s\n' '--- frontend manifest ---'
cat frontend/package.json

printf '%s\n' '--- relevant source references ---'
rg -n -C 4 '`@babel/standalone`|babel\.(parse|traverse)|babel\.packages' frontend/src frontend/package.json

printf '%s\n' '--- lockfile references ---'
rg -n -C 2 '`@babel/standalone`|node_modules/@babel/standalone|babel/standalone' . \
  -g 'package-lock.json' -g 'yarn.lock' -g 'pnpm-lock.yaml' -g 'npm-shrinkwrap.json' || true

Repository: Canopus-Labs/PrepPilot

Length of output: 3637


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- component ---'
cat -n frontend/src/components/CodeComplexityProfiler.jsx

printf '%s\n' '--- root package configuration ---'
cat package.json

printf '%s\n' '--- all lockfile package entries for the dependency ---'
for lockfile in package-lock.json frontend/package-lock.json backend/package-lock.json; do
  if [ -f "$lockfile" ]; then
    printf '%s\n' "--- $lockfile ---"
    jq -r '
      if .packages then
        .packages | to_entries[] | select(.key | contains("`@babel/standalone`")) | .key + " " + (.value.version // "")
      elif .dependencies then
        paths(scalars) as $p | select(($p | join("/")) | contains("`@babel/standalone`")) | (($p | join("/")) + " " + (getpath($p) | tostring))
      else empty end
    ' "$lockfile" 2>/dev/null || true
  fi
done

Repository: Canopus-Labs/PrepPilot

Length of output: 4005


🌐 Web query:

@babel/standalone parse traverse API Babel.packages official documentation

💡 Result:

The @babel/standalone package provides access to internal Babel tooling packages, including parser and traverse, through the Babel.packages object [1][2]. When you load @babel/standalone in a browser environment, it exposes a global Babel object that contains these packages [1]. You can access them as follows: Babel.packages.parser [1][2] Babel.packages.traverse [1][2] Other available packages include Babel.packages.generator, Babel.packages.template, and Babel.packages.types [1][2]. Important usage notes: - These internal packages are exposed specifically for use within non-Node.js (browser) environments where standard module imports are not available [3]. - While these packages are made available, @babel/standalone does not provide a direct top-level parse API outside of these namespaced packages [4]. - You should generally prefer importing these packages directly (e.g., import { parse } from "@babel/parser") if you are using a bundler or working in a Node.js environment [3].

Citations:


Declare @babel/standalone and use its supported APIs.

Add @babel/standalone to frontend/package.json and update frontend/package-lock.json. The current babel.parse and babel.traverse calls are not top-level @babel/standalone APIs; use babel.packages.parser and babel.packages.traverse instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/CodeComplexityProfiler.jsx` at line 2, Declare
`@babel/standalone` in frontend/package.json and synchronize
frontend/package-lock.json. In CodeComplexityProfiler, replace unsupported
top-level babel.parse and babel.traverse calls with the supported
babel.packages.parser and babel.packages.traverse APIs.

Comment on lines +13 to +21
const ast = babel.parse(code, {
presets: ['env'],
});

let loopCount = 0;
let maxDepth = 0;

// Simple custom traversal to detect loops
babel.traverse(ast, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Official Babel documentation for @babel/standalone: how should an application access the parser and traversal APIs, and are Babel.parseandBabel.traverse supported top-level APIs?

💡 Result:

In @babel/standalone, the parser and traversal APIs are not directly exposed as top-level methods on the global Babel object [1][2]. Instead, they are accessible through the Babel.packages object [1][2]. To access these functionalities, you should use the following paths: - Parser: Babel.packages.parser [1][2] - Traversal: Babel.packages.traverse [1][2] The methods Babel.parse and Babel.traverse are not supported as top-level APIs on the Babel object [1][2]. You must access them via the namespaced properties shown above. For example, if you wish to use the parser, you would access it via Babel.packages.parser. Likewise, traversal is accessed via Babel.packages.traverse [1][2]. The full list of internal packages exposed on the Babel.packages object includes: - Babel.packages.generator [1][2] - Babel.packages.parser [1][2] - Babel.packages.template [1][2] - Babel.packages.traverse [1][2] - Babel.packages.types [1][2]

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

file="$(git ls-files | grep -F 'frontend/src/components/CodeComplexityProfiler.jsx' | head -n1)"
printf '%s\n' "FILE=$file"
wc -l "$file"
sed -n '1,180p' "$file"

printf '%s\n' '--- frontend/package.json ---'
cat frontend/package.json

printf '%s\n' '--- Babel API references ---'
rg -n --glob '!node_modules/**' '`@babel/standalone`|babel\.(parse|traverse)|babel\.packages\.(parser|traverse)' frontend

Repository: Canopus-Labs/PrepPilot

Length of output: 4869


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- package manifests and lockfiles ---'
git ls-files | grep -E '(^|/)(package(-lock)?\.json|pnpm-lock\.yaml|yarn\.lock)$' || true

printf '%s\n' '--- `@babel/standalone` declarations and lockfile entries ---'
rg -n --hidden --glob '!**/.git/**' --glob '!**/node_modules/**' \
  '"`@babel/standalone`"|`@babel/standalone` frontend|`@babel/standalone`' . || true

printf '%s\n' '--- component call sites ---'
rg -n --glob '!**/node_modules/**' 'CodeComplexityProfiler|analyzeCode|setComplexity|setError' frontend/src frontend 2>/dev/null || true

printf '%s\n' '--- relevant source structure ---'
ast-grep outline frontend/src/components/CodeComplexityProfiler.jsx

Repository: Canopus-Labs/PrepPilot

Length of output: 20884


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
import json
from pathlib import Path

source = Path("frontend/src/components/CodeComplexityProfiler.jsx").read_text()
manifest = json.loads(Path("frontend/package.json").read_text())
lock = json.loads(Path("frontend/package-lock.json").read_text())

print("frontend_dependency_declared=", "`@babel/standalone`" in manifest.get("dependencies", {}) or "`@babel/standalone`" in manifest.get("devDependencies", {}))
print("frontend_lock_root_declared=", "`@babel/standalone`" in lock.get("packages", {}).get("", {}).get("dependencies", {}))
print("frontend_lock_package_present=", any(
    key.endswith("/node_modules/@babel/standalone") or key == "node_modules/@babel/standalone"
    for key in lock.get("packages", {})
))
print("top_level_parse_call=", "babel.parse(" in source)
print("namespaced_parse_call=", "babel.packages.parser.parse(" in source)
print("top_level_traverse_call=", "babel.traverse(" in source)
print("namespaced_traverse_call=", "babel.packages.traverse(" in source)

for node in ("ForStatement", "WhileStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement"):
    print(f"visitor_{node}=", f"{node}(path)" in source)
print("complexity_cleared_on_error=", "setComplexity(null)" in source[source.index("} catch"):])
PY

printf '%s\n' '--- frontend lockfile package metadata ---'
python3 - <<'PY'
import json
from pathlib import Path
lock = json.loads(Path("frontend/package-lock.json").read_text())
for key, value in lock.get("packages", {}).items():
    if "babel" in key.lower():
        print(key, value.get("version"))
PY

printf '%s\n' '--- root package declarations ---'
cat package.json

Repository: Canopus-Labs/PrepPilot

Length of output: 1741


Fix the Babel dependency and analyzer state before merging.

  • Add @babel/standalone to frontend/package.json and its lockfile.
  • Use babel.packages.parser.parse and babel.packages.traverse. The top-level calls are unsupported.
  • Add visitors for ForInStatement, ForOfStatement, and DoWhileStatement if all loops must count.
  • Clear complexity in the error path to prevent stale results.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/CodeComplexityProfiler.jsx` around lines 13 - 21, Add
`@babel/standalone` to frontend/package.json and the lockfile, then update
CodeComplexityProfiler to parse and traverse through babel.packages.parser.parse
and babel.packages.traverse. Extend its traversal visitors to count
ForInStatement, ForOfStatement, and DoWhileStatement, and clear the complexity
state in the error path so stale results are not retained.

Comment on lines +21 to +32
babel.traverse(ast, {
ForStatement(path) {
loopCount++;
const depth = path.getAncestry().filter(p => p.isLoop()).length;
maxDepth = Math.max(maxDepth, depth);
},
WhileStatement(path) {
loopCount++;
const depth = path.getAncestry().filter(p => p.isLoop()).length;
maxDepth = Math.max(maxDepth, depth);
}
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Include all JavaScript loop node types.

for...in, for...of, and do...while loops are not counted. For example, a single for (const item of items) loop reports zero loops and O(1). Add visitors for ForInStatement, ForOfStatement, and DoWhileStatement.

Proposed fix
       babel.packages.traverse(ast, {
         ForStatement(path) {
           loopCount++;
           const depth = path.getAncestry().filter(p => p.isLoop()).length;
           maxDepth = Math.max(maxDepth, depth);
         },
+        ForInStatement(path) {
+          loopCount++;
+          const depth = path.getAncestry().filter(p => p.isLoop()).length;
+          maxDepth = Math.max(maxDepth, depth);
+        },
+        ForOfStatement(path) {
+          loopCount++;
+          const depth = path.getAncestry().filter(p => p.isLoop()).length;
+          maxDepth = Math.max(maxDepth, depth);
+        },
         WhileStatement(path) {
           loopCount++;
           const depth = path.getAncestry().filter(p => p.isLoop()).length;
           maxDepth = Math.max(maxDepth, depth);
+        },
+        DoWhileStatement(path) {
+          loopCount++;
+          const depth = path.getAncestry().filter(p => p.isLoop()).length;
+          maxDepth = Math.max(maxDepth, depth);
         }
       });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/CodeComplexityProfiler.jsx` around lines 21 - 32,
Extend the loop visitors in the Babel traversal used by the complexity profiler
to include ForInStatement, ForOfStatement, and DoWhileStatement alongside
ForStatement and WhileStatement. Ensure each new visitor increments loopCount
and updates maxDepth using the same ancestry-based depth calculation.

Comment on lines +45 to +48
} catch (err) {
setError("Failed to parse code. Please ensure valid JavaScript.");
console.error(err);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear the previous result when parsing fails.

If a valid analysis is followed by invalid code, complexity retains the old result. The UI then shows stale loop metrics with the parse error. Clear complexity in the catch block.

Proposed fix
     } catch (err) {
+      setComplexity(null);
       setError("Failed to parse code. Please ensure valid JavaScript.");
       console.error(err);
     }
📝 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
} catch (err) {
setError("Failed to parse code. Please ensure valid JavaScript.");
console.error(err);
}
} catch (err) {
setComplexity(null);
setError("Failed to parse code. Please ensure valid JavaScript.");
console.error(err);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/CodeComplexityProfiler.jsx` around lines 45 - 48,
Update the parse-error catch block in CodeComplexityProfiler to clear the
existing complexity result before setting the parse error, ensuring stale
analysis metrics are not displayed after invalid code is submitted.

@github-actions github-actions Bot added the merge ready PR is mergeable and has no conflicts label Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge ready PR is mergeable and has no conflicts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant