feat(jscan): port module and directory quality rollups - #49
Open
DaisukeYoda wants to merge 1 commit into
Open
Conversation
Closes #31. Adds pyscn's per-module hotspots (#686) and directory rollups (#533/#687) to jscan: - `by_directory` on the complexity response, aggregating the reported functions per directory relative to the deepest directory containing every analyzed file - `module_quality` on the analyze output, joining each file's line count, complexity rollups, and dead-code rollups with its module name Both rollups are derived before the presentation filters, so a report narrowed by min_complexity or min_severity still measures what each module carries. The aggregation sits in the service layer rather than pyscn's use-case seam because jscan's analyze command calls the services directly. Reported through JSON, YAML, text, CSV, and HTML (a directory table in the complexity tab, a new Modules tab). nesting_depth had no working backing metric: CalculateNestingDepth was never called, and it counted a function's control structures instead of measuring how deeply they nest, so the published per-function value was always 0. It now measures real depth — an else-if chain stays flat, a catch clause stays at its try's level, and nested functions are measured separately — and the directory rollups aggregate it. Divergences from pyscn are recorded in SYNC.md: no cognitive complexity, no function_count (identical to analyzed_function_count in jscan), lines_of_code sourced from the complexity service, and no HTML table sorting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #31.
Ports pyscn's per-module quality hotspots (pyscn#686) and directory quality rollups (pyscn#687, issue #533) to jscan.
What this adds
by_directoryon the complexity response — function count, average/max complexity, high-risk count, and average/max nesting depth per directory. Paths are relative to the deepest directory containing every analyzed file, ranked worst-first.module_qualityon the analyze output — one entry per file joining its line count, complexity rollups, and dead-code rollups, with the module name from dependency analysis.Both are reported through JSON, YAML, text, CSV, and HTML (a directory table in the Complexity tab, a new Modules tab).
As upstream, the rollups are computed before the presentation filters:
min_complexityandmin_severitychange what the report shows without changing what a module is measured as carrying. Both response types carry ajson:"-"ModuleRollupsmap for this, and the behavior is covered by tests that run the same project at two filter settings.The aggregation sits in the service layer rather than pyscn's use-case seam, because jscan's
analyzecommand calls the services directly —BuildModuleQualitylives next to the existingBuildAnalyzeSummary.nesting_depth was not actually available
The issue assumed jscan already computed per-function
NestingDepth. It didn't:CalculateNestingDepthwas never called from production code, and its implementation incremented a counter per control structure without ever decrementing, so it counted control structures rather than measuring depth. The published per-functionnesting_depthwas always0.Rather than ship two permanently-zero columns, this PR implements it: an
else ifcontinues the chain itsifopened, acatchclause stays at itstry's level, nested functions are measured separately, and the value is wired into the complexity result. Ten unit tests cover the rules. Nothing scores onNestingDepth, so health scores are unaffected.Deliberate divergences from pyscn
Recorded in
jscan/SYNC.mdunder a new "Ported with divergences" section:average_cognitive_complexity— cognitive complexity is still unported; the field is absent rather than reported as zerofunction_count— jscan records a complexity result for every function it parses, so it would always equalanalyzed_function_countlines_of_codecomes from the complexity service, the only per-file reader already holding the file content; line counting matches pyscn'scountSourceLinesVerification
gofmt,go vet, and the full test suite pass.make lintwas not run: the locally installed golangci-lint is v1 and the repo config is v2.Docs updated:
jscan/CHANGELOG.md,jscan/SYNC.md,website/docs/output/json-schema.md,website/docs/output/html-report.md.🤖 Generated with Claude Code