Conversation
* docs: restructure README and add client setup guide README cut from 707 to ~220 lines. Per-client config blocks, pipeline internals, and eval harness moved to dedicated docs where they belong. Screenshots and CLI previews moved up before the setup details. - docs/client-setup.md: new file with all 7 client configs (stdio + HTTP where supported), fallback single-project setup, and local build testing - docs/capabilities.md: add practical routing examples and selection_required response shape (moved from README) - CONTRIBUTING.md: add eval harness section (moved from README) - templates/mcp/stdio/.mcp.json + http/.mcp.json: copy-pasteable config templates - tests/mcp-client-templates.test.ts: regression tests for template validity and README/capabilities doc coverage - package.json: add docs/client-setup.md to files array * Update tests/mcp-client-templates.test.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
- Cache defaultCodeExtensions at module level in isCodeFile so callers that pass no pre-built set avoid a per-call Set allocation - Add motivation comment to scripts/run-vitest.mjs explaining why the wrapper exists instead of invoking vitest directly - Always assign runtimeOverrides in applyServerConfig even when empty, so stale overrides don't persist if config hints are later removed
Upstream the React and Next.js analyzer work from issue #2 and the aolin480 fork through the existing registry surfaces with focused tests and docs updates.
Greptile SummaryThis PR ships the long-awaited dedicated React and Next.js analyzers (closes issue #2 from the olin480 fork), wires them into the existing analyzer registry, and fixes Angular metadata to stop claiming projects that don't use Angular. Several supporting improvements land alongside: a shared Key changes:
Issues found:
Confidence Score: 4/5Safe to merge with the P1 The core analyzer logic is well-structured, correctly prioritised, and covered by new tests. The P1 issue (dead src/core/indexer.ts (enabled flag), src/types/index.ts (type-agnosticism rule), and src/analyzers/react/index.ts + src/analyzers/nextjs/index.ts (duplicated helpers).
|
| Filename | Overview |
|---|---|
| src/analyzers/react/index.ts | New ReactAnalyzer with component/hook/context detection via AST walk; contains a broad JSX heuristic regex and duplicates helpers from the Next.js analyzer. |
| src/analyzers/nextjs/index.ts | New NextJsAnalyzer with App/Pages Router detection, route-path computation, and metadata export detection; duplicates several helper functions from the React analyzer. |
| src/analyzers/shared/metadata.ts | New shared metadata helpers (package info reading, stats loading, version normalisation, ENOENT guard); well-structured with appropriate size-guard for index files. |
| src/core/indexer.ts | Fixes metadata-merge precedence (base wins over incoming) and adds nextjs/react to the default analyzer config with enabled: false — but the enabled flag is never read anywhere. |
| src/types/index.ts | Adds 'nextjs' to FrameworkInfo.type union and nextjs?: AnalyzerConfig to CodebaseConfig.analyzers — both add framework-specific names to core shared types, violating the AGENTS.md type-agnosticism rule. |
| src/index.ts | Registers new analyzers and changes runtimeOverrides assignment to unconditional, which now calls getOrCreateProject for every configured project even when no overrides exist. |
| src/analyzers/angular/index.ts | Tightened Angular metadata: now only sets framework metadata when @angular/core is actually present, and silences expected ENOENT errors from file-not-found conditions. |
| tests/indexer-metadata.test.ts | Adds test for Next.js-over-React metadata precedence and guards against double registration; new tests are coherent and cover the priority-merge fix. |
| tests/react-analyzer.test.ts | New tests covering component/hook/context/ecosystem-signal detection; comprehensive coverage of the main analyzer paths. |
| tests/nextjs-analyzer.test.ts | New tests for App/Pages Router detection, route-group filtering, system-file exclusion, and metadata stats loading from index; good coverage of edge cases. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[File arrives at indexer] --> B{AnalyzerRegistry.findAnalyzer}
B --> C{preferredAnalyzer set?}
C -- Yes --> D[Use preferred if canAnalyze passes]
C -- No --> E[Iterate sorted analyzers by priority]
E --> F{NextJsAnalyzer priority=90\ncanAnalyze?}
F -- Yes --> G[NextJsAnalyzer.analyze\nRoute/API detection\nApp vs Pages Router]
F -- No --> H{ReactAnalyzer priority=80\ncanAnalyze?}
H -- Yes --> I[ReactAnalyzer.analyze\nComponents / Hooks / Context]
H -- No --> J{AngularAnalyzer priority=100\ncanAnalyze?}
J -- Yes --> K[AngularAnalyzer.analyze]
J -- No --> L[GenericAnalyzer priority=10]
G --> M[AnalysisResult]
I --> M
K --> M
L --> M
M --> N[createChunksFromCode]
N --> O[CodeChunk with metadata]
P[detectMetadata called] --> Q[All analyzers call detectCodebaseMetadata]
Q --> R[mergeMetadata: base.framework wins over incoming]
R --> S{Next.js deps found?}
S -- Yes --> T[framework.type = nextjs]
S -- No --> U{React deps found?}
U -- Yes --> V[framework.type = react]
U -- No --> W[framework.type from Angular/Generic]
Comments Outside Diff (5)
-
src/types/index.ts, line 1611-1619 (link)Framework-specific names in shared types violate the type-agnosticism rule
Per the project code-separation rules in AGENTS.md, framework-specific field names should live exclusively in
src/analyzers/<framework>/and shared interfaces should use open-ended extension via index signatures.This diff makes two additions that work against that principle:
'nextjs'is appended to theFrameworkInfo.typeunion at line 1611, embedding a framework identifier in a shared type.- A named
nextjs?: AnalyzerConfigproperty is added toCodebaseConfig.analyzersat line 1619, alongside the existing catch-all index signature that already covers it without a dedicated key.
The named
nextjs?property is both redundant (the index signature already satisfies type-safe lookups) and a violation of the stated rule. Removing the explicit named property and relying on the index signature is sufficient.Context Used: Custom context (source)
-
src/analyzers/react/index.ts, line 794 (link)Broad JSX heuristic regex risks false positives on non-React files
/<[A-Za-z][^>]*>/.test(content)
This pattern matches any
<Tag...>sequence, including HTML embedded in JSDoc/TSDoc comments (e.g./** <Foo bar> */), template literals containing HTML strings, or XML-like content in config files. A plain TypeScript utility file with a single/** <br> */doc comment would be misidentified as React.Consider narrowing the heuristic to require that the tag name starts with an uppercase letter (a conventional React component marker):
-
src/analyzers/react/index.ts, line 1077-1107 (link)Duplicated helpers between React and Next.js analyzers
appendExports,getImportSpecifierName,getPackageName, anddetectDependencyListare defined identically (or near-identically) in bothsrc/analyzers/react/index.tsandsrc/analyzers/nextjs/index.ts. The sharedsrc/analyzers/shared/metadata.tsalready exists as the right home for cross-analyzer utilities.Keeping two independent copies means any future bug fix or behavioural change must be applied in two places. Moving them to
shared/metadata.ts(or a newshared/ast-helpers.ts) would also make the slight implementation divergence ingetImportSpecifierNamevisible and intentional rather than accidental. -
src/index.ts, line 1540-1541 (link)Unconditional
getOrCreateProjectinitialises state for every configured projectThe original guard
if (Object.keys(runtimeOverrides).length > 0)intentionally avoided creating project-state entries when there were no overrides to apply. The new unconditional form now callsgetOrCreateProjectfor every project in the server config, even whenbuildProjectRuntimeOverridesreturns{}.Additionally, assigning
project.runtimeOverrides = {}clears any previously-set overrides rather than leaving them untouched — which might be the intended semantics on config reload, but it changes the contract silently and is unrelated to the React/Next.js analyzer work. A comment noting the intent would help. -
src/analyzers/react/index.ts, line 1165-1177 (link)containsJsx/walkAstdoes not short-circuit after the first JSX node is foundcontainsJsxsetsfound = trueinside the visitor, butwalkAstcontinues traversing the entire remaining subtree regardless. For a large function body this means unnecessary work on every component detection call.Guarding with
if (!found)before the check avoids redundant work once a match is detected:function containsJsx(node: TSESTree.Node | TSESTree.Node[] | null): boolean { if (!node) return false; let found = false; walkAst(node, (candidate) => { if (!found && (candidate.type === 'JSXElement' || candidate.type === 'JSXFragment')) { found = true; } }); return found; }
Reviews (1): Last reviewed commit: "feat: add react and nextjs analyzers" | Re-trigger Greptile
| nextjs: { enabled: false, priority: 90 }, | ||
| react: { enabled: false, priority: 90 }, | ||
| vue: { enabled: false, priority: 90 }, |
There was a problem hiding this comment.
enabled: false is dead configuration — analyzers always run when registered
nextjs and react are now unconditionally registered in src/index.ts, src/cli.ts, and src/lib.ts, but their default config entries say enabled: false. A grep across the entire src/core/ directory confirms the enabled field is never read — AnalyzerRegistry.findAnalyzer uses only canAnalyze and priority, ignoring the config flag entirely.
As a result, the React and Next.js analyzers are fully active for any file that passes their canAnalyze heuristics (e.g., all .tsx/.jsx files), regardless of what the config says. The enabled: false entries are misleading dead state that:
- Implies to users and operators that these analyzers are opt-in, when they are always on.
- Could create future confusion if someone later wires up the
enabledflag and changes existing behaviour.
Either enforce the flag in AnalyzerRegistry.findAnalyzer / detectMetadata, or set enabled: true to match the actual runtime behaviour:
| nextjs: { enabled: false, priority: 90 }, | |
| react: { enabled: false, priority: 90 }, | |
| vue: { enabled: false, priority: 90 }, | |
| nextjs: { enabled: true, priority: 90 }, | |
| react: { enabled: true, priority: 90 }, |
|
Functional-only merge gate triage for this PR: Verification run (local):
Blocker classification (functional gate):
Decision for this gate:
Follow-up (recommended, separate PR/issue):
|
Summary
Testing
Notes
Attribution
Related #2