cog_complex

Cognitive Complexity score analyzer for MoonBit source code

cognitive-complexity
complexity-score
lint
analysis
cli
moon add pocket7878/cog_complex@0.1.0
Download zip
Version
0.1.0
License
Apache-2.0
Last updated
last month
Downloads
18

Dependencies

README

#cog_complex

MoonBit projects can run this tool to measure a Cognitive Complexity score for each top-level function and method in .mbt files.

cog_complex reports a small integer for each function using a Cognitive-Complexity-style model, where a higher number means the control flow is harder to read. It is not a general complexity analyzer for time complexity, space complexity, or cyclomatic complexity. The implementation is specific to MoonBit and works from moonbitlang/parser AST nodes.

#Installation

Use it from this repository with moon run:

moon run cmd/cog_complex -- path/to/moonbit/project

Or install the command locally from a checkout:

moon install ./cmd/cog_complex cog_complex path/to/moonbit/project

Once the package is published, it can be installed from the registry:

moon install pocket7878/cog_complex/cmd/cog_complex cog_complex path/to/moonbit/project

If no path is passed, the current directory is scanned recursively. _build, .mooncakes, and .git are skipped.

#Usage

Scan the current project:

moon run cmd/cog_complex -- .

Scan a single package, directory, or file:

moon run cmd/cog_complex -- src moon run cmd/cog_complex -- src/parser moon run cmd/cog_complex -- src/parser/token.mbt

Output is line oriented:

src/main/main.mbt:main 3

Each line has:

<path>:<function-or-method-name> <complexity-score>

Methods are reported as Type::method:

src/counter.mbt:Counter::sign 1

For a simple local quality gate, combine the output with a small script and fail CI when any function is over your threshold. This project keeps all functions at 15 or below:

moon run cmd/cog_complex -- . | awk '$NF > 15 { print; bad = 1 } END { exit bad }'

#How Scores Are Counted

The Cognitive Complexity score starts at 0 for each top-level function or method. Control-flow syntax adds structural increments, and nested control flow adds more.

For example, an else if chain adds one point per branch:

///|
fn words(n : Int) -> String {
if n == 1 { // +1
"one"
} else if n == 2 { // +1
"two"
} else {
"many"
}
} // Complexity score = 2

A match is usually easier to scan because cases do not each add a branch increment:

///|
fn words(n : Int) -> String {
match n { // +1
1 => "one"
2 => "two"
_ => "many"
}
} // Complexity score = 1

Nested loops and nested branches include the current nesting depth:

///|
fn first_positive(rows : Array[Array[Int]]) -> Int {
for row in rows { // +1
for x in row { // +2 (nesting = 1)
if x > 0 { // +3 (nesting = 2)
return x
}
}
}
0
} // Complexity score = 6

Labeled jumps add a fundamental increment because the reader has to track the target label:

///|
fn scan(xs : Array[Int]) -> Int {
outer~: for i = 0; i < xs.length(); i = i + 1 { // +1
if xs[i] < 0 { // +2
break outer~ // +1
}
}
0
} // Complexity score = 4

#Current Rules

The scoring model follows Cognitive Complexity principles for structured code:

  • structural control flow increments for if, guard, match, lexmatch, for, foreach, while, list comprehensions, and catch cases
  • extra nesting increments for nested control flow
  • else if chains do not add an extra nesting increment
  • match cases are not counted as separate branches
  • try, try?, try!, return, raise, and unlabeled break/continue are traversed but do not add jump increments by themselves
  • labeled break and continue add one fundamental increment
  • function literals and local functions add nesting level without adding a structural increment
  • logical operator sequences add one increment per sequence, including outside conditions
  • direct recursive function and method calls add one increment

The implementation uses moonbitlang/parser and analyzes MoonBit AST nodes instead of scanning source text.

#Development

Run the full validation loop:

moon test moon coverage analyze moon coverage report -f summary moon run cmd/cog_complex -- . moon info moon fmt

The repository currently uses 85% coverage and a maximum Cognitive Complexity score of 15 as quality gates.

#Publish Checklist

Before publishing:

moon test moon coverage analyze moon coverage report -f summary moon run cmd/cog_complex -- . moon info moon fmt moon package --list moon install --dry-run ./cmd/cog_complex

moon package --list should complete without manifest warnings, and moon install --dry-run ./cmd/cog_complex should report that it would install the cog_complex binary.

#
FunctionScore

pub(all) struct FunctionScore {
name : String
score : Int
}

A complexity score score for a top-level function or method.

name is the source-level function name. Methods are reported as Type::method.

#
score_file

fn score_file(path : String) -> Array[FunctionScore] raise
IOError

Parse a MoonBit source file and score every top-level function body.

#
score_source

fn score_source(source : String) -> Array[FunctionScore]

Parse MoonBit source text and score every top-level function body.

Invalid source returns an empty result because the parser diagnostics make the AST unreliable for scoring.

Source Files

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io