Sign in

    cog_complex

    Cognitive Complexity score analyzer for MoonBit source code

    cognitive-complexity
    complexity-score
    lint
    analysis
    cli
    Download zip
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    4 months ago
    Downloads
    30

    #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