Skip to content

Detectors

Detectors encapsulate individual rule checks by language.

Bash

mcp_zen_of_languages.languages.bash.detectors

Rule detectors for Bash/shell code quality and robustness checks.

Each detector in this module targets a specific shell scripting anti-pattern — from missing set -euo pipefail and unquoted variable expansions to legacy backtick syntax and absent signal handlers. Detectors scan source lines with regex patterns because no Python-native Bash AST is currently integrated.

See Also

BashAnalyzer: The analyzer that wires these detectors into its pipeline.

Classes

BashStrictModeDetector

BashStrictModeDetector()

Bases: ViolationDetector[BashStrictModeConfig], LocationHelperMixin

Detect scripts missing the unofficial Bash strict mode header.

Without set -euo pipefail, a script silently continues after command failures (-e), uses undefined variables without error (-u), and masks failures in pipelines (pipefail). This is the number-one cause of "it worked on my machine" CI failures. The detector searches the entire file content for the exact pragma string.

Note

Place set -euo pipefail immediately after the shebang line so that every subsequent command runs under strict error handling.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashStrictModeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashStrictModeConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashStrictModeConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "set -euo pipefail" not in context.code:
        return [
            self.build_violation(
                config,
                contains="set -euo pipefail",
                suggestion="Add 'set -euo pipefail' near the top of the script.",
            ),
        ]
    return []

BashQuoteVariablesDetector

BashQuoteVariablesDetector()

Bases: ViolationDetector[BashQuoteVariablesConfig], LocationHelperMixin

Detect unquoted variable expansions that cause word-splitting bugs.

When $var appears outside double quotes, the shell performs word splitting and pathname expansion on its value. A filename containing spaces or glob characters can silently break rm, mv, or loop logic. This detector flags lines containing $ variable references that lack surrounding double quotes.

Note

Always write "$var" instead of bare $var to prevent word splitting and globbing surprises.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashQuoteVariablesConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashQuoteVariablesConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashQuoteVariablesConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="quote",
            location=Location(line=idx, column=1),
            suggestion='Quote variable expansions like "$var".',
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"\$\w+", line) and '"' not in line
    ]
    return violations

BashEvalUsageDetector

BashEvalUsageDetector()

Bases: ViolationDetector[BashEvalUsageConfig], LocationHelperMixin

Detect usage of eval which enables code injection attacks.

eval re-parses its arguments as shell commands, making scripts vulnerable to injection when any part of the evaluated string comes from user input, environment variables, or external files. This detector scans every line for the eval keyword and reports its exact position.

Note

Replace eval with arrays for dynamic command construction or case statements for dispatching, both of which are injection-safe.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashEvalUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashEvalUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashEvalUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="eval",
            location=Location(line=idx, column=line.find("eval") + 1),
            suggestion="Avoid eval; use arrays or case statements instead.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "eval" in line
    ]
    return violations

BashDoubleBracketsDetector

BashDoubleBracketsDetector()

Bases: ViolationDetector[BashDoubleBracketsConfig], LocationHelperMixin

Detect single-bracket [ ] test expressions that should use [[ ]].

The POSIX [ command is an external binary with surprising parsing rules — unquoted variables inside [ ] can cause syntax errors when empty, and pattern matching is unavailable. Bash's built-in [[ ]] handles empty strings safely, supports =~ regex matching, and does not perform word splitting on variables.

Note

[[ ]] is a Bash extension. If POSIX portability is required, quote all variables inside [ ] instead.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashDoubleBracketsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashDoubleBracketsConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashDoubleBracketsConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="[",
            location=Location(line=idx, column=1),
            suggestion="Prefer [[ ]] over [ ] for conditionals.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"\[[^\\[]", line) and "[[" not in line
    ]
    return violations

BashCommandSubstitutionDetector

BashCommandSubstitutionDetector()

Bases: ViolationDetector[BashCommandSubstitutionConfig], LocationHelperMixin

Detect legacy backtick command substitution syntax.

Backtick-delimited command substitution (cmd) cannot be nested without cumbersome escaping, is visually ambiguous with single quotes in some fonts, and is considered deprecated in modern shell style guides. This detector flags every backtick occurrence and recommends the $(cmd) form, which nests cleanly and is universally supported.

Note

$(...) is supported by all POSIX-compliant shells and should be the default choice for command substitution.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashCommandSubstitutionConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashCommandSubstitutionConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashCommandSubstitutionConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="`",
            location=Location(line=idx, column=line.find("`") + 1),
            suggestion="Use $(...) instead of backticks.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "`" in line
    ]
    return violations

BashReadonlyConstantsDetector

BashReadonlyConstantsDetector()

Bases: ViolationDetector[BashReadonlyConstantsConfig], LocationHelperMixin

Detect ALL_CAPS assignments that are not declared readonly.

Shell constants (paths, configuration values, magic strings) are conventionally named in ALL_CAPS but remain mutable unless explicitly declared with readonly. Accidental reassignment of a constant deep in a script can produce silent, hard-to-debug failures. This detector flags top-level ALL_CAPS assignments lacking readonly.

Note

Use readonly MY_CONST="value" or declare -r to make constants truly immutable.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashReadonlyConstantsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashReadonlyConstantsConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashReadonlyConstantsConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="readonly",
            location=Location(line=idx, column=1),
            suggestion="Declare constants with readonly.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.match(r"^[A-Z][A-Z0-9_]*=", line) and "readonly" not in line
    ]
    return violations

BashExitCodeChecksDetector

BashExitCodeChecksDetector()

Bases: ViolationDetector[BashExitCodeConfig], LocationHelperMixin

Detect external commands whose exit codes are silently ignored.

Even with set -e, some command failures can slip through (e.g., commands on the left side of && or inside if conditions). This detector identifies standalone command invocations that are not guarded by ||, &&, or explicit $? checks, flagging the first unguarded command it finds.

Note

Guard critical commands with cmd || handle_error or check $? immediately after execution.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashExitCodeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(  # noqa: C901
    self,
    context: AnalysisContext,
    config: BashExitCodeConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashExitCodeConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    lines = context.code.splitlines()
    for idx, line in enumerate(lines, start=1):
        stripped = line.strip()
        if not stripped or stripped.startswith("#"):
            continue
        if re.match(r"^[A-Za-z_][A-Za-z0-9_]*=", stripped):
            continue
        if stripped.startswith("export ") and "=" in stripped:
            continue
        if re.match(r"^\w+\s*\(\)\s*\{", stripped):
            continue
        if re.match(
            r"^(if|then|elif|else|fi|for|while|until|case|select|do|done)\b",
            stripped,
        ):
            continue
        if stripped.startswith(("set ", "{", "}")):
            continue
        if re.match(r"^(return|exit)\b", stripped):
            continue
        if "||" in stripped or "&&" in stripped or "$?" in stripped:
            continue
        next_line = lines[idx] if idx < len(lines) else ""
        if "$?" in next_line:
            continue
        if re.match(r"^[A-Za-z0-9_./-]+", stripped):
            violations.append(
                self.build_violation(
                    config,
                    contains="exit code",
                    location=Location(line=idx, column=1),
                    suggestion=(
                        "Check exit codes with `||`, `&&`, or explicit `$?` tests."
                    ),
                ),
            )
            break
    return violations

BashFunctionUsageDetector

BashFunctionUsageDetector()

Bases: ViolationDetector[Bash006Config], LocationHelperMixin

Detect long scripts that lack function decomposition.

A linear Bash script without functions becomes unreadable and un-testable as it grows. This detector counts non-comment, non-blank lines and flags scripts exceeding max_script_length_without_functions when no function or name() declaration is present.

Note

Extract repeated or logically distinct blocks into named functions so each unit can be tested, logged, and reused independently.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: Bash006Config

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: Bash006Config,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (Bash006Config): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    lines = [
        line
        for line in context.code.splitlines()
        if line.strip() and not line.strip().startswith("#")
    ]
    has_function = any(
        re.match(r"^\s*(?:function\s+)?\w+\s*\(\)\s*\{", line) for line in lines
    )
    max_len = config.max_script_length_without_functions or 50
    if not has_function and len(lines) > max_len:
        return [
            self.build_violation(
                config,
                contains="function",
                location=Location(line=1, column=1),
                suggestion="Extract reusable logic into functions.",
            ),
        ]
    return []

BashLocalVariablesDetector

BashLocalVariablesDetector()

Bases: ViolationDetector[BashLocalVariablesConfig], LocationHelperMixin

Detect function-scoped variables missing the local keyword.

Bash variables are global by default — assigning name=value inside a function pollutes the caller's namespace and can overwrite unrelated variables. This detector tracks whether the script is inside a function body and flags variable assignments that omit local.

Note

Always prefix function-internal assignments with local to prevent accidental namespace collisions.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashLocalVariablesConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashLocalVariablesConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashLocalVariablesConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    in_function = False
    for idx, line in enumerate(context.code.splitlines(), start=1):
        stripped = line.strip()
        if re.match(r"^\s*(?:function\s+)?\w+\s*\(\)\s*\{", line):
            in_function = True
            continue
        if in_function and stripped.startswith("}"):
            in_function = False
            continue
        if not in_function:
            continue
        if re.match(
            r"^[A-Za-z_][A-Za-z0-9_]*=",
            stripped,
        ) and not stripped.startswith("local "):
            violations.append(
                self.build_violation(
                    config,
                    contains="local",
                    location=Location(line=idx, column=1),
                    suggestion="Declare function variables with local.",
                ),
            )
            break
    return violations

BashArgumentValidationDetector

BashArgumentValidationDetector()

Bases: ViolationDetector[BashArgumentValidationConfig], LocationHelperMixin

Detect scripts that use positional arguments without validation.

Scripts referencing $1, $@, or $* without checking $# or using getopts will produce cryptic errors — or worse, silently operate on empty values — when invoked with missing arguments. This detector flags the absence of argument-count guards.

Note

Validate arguments early with if [[ $# -lt N ]] or use getopts for option parsing to fail fast with a clear message.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashArgumentValidationConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashArgumentValidationConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashArgumentValidationConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    uses_args = bool(re.search(r"\$(?:[1-9]|@|\*)", code))
    has_validation = "$#" in code or "getopts" in code
    if uses_args and not has_validation:
        return [
            self.build_violation(
                config,
                contains="$#",
                location=Location(line=1, column=1),
                suggestion="Validate arguments with `$#` checks or getopts.",
            ),
        ]
    return []

BashMeaningfulNamesDetector

BashMeaningfulNamesDetector()

Bases: ViolationDetector[Bash011Config], LocationHelperMixin

Detect overly short or cryptic variable names in shell scripts.

Single-character names like x or t outside of loop counters (i, j, k) and ALL_CAPS constants make scripts harder to maintain. This detector extracts variable assignments, skips uppercase constants and conventional loop vars, and flags names shorter than min_variable_name_length.

Note

Descriptive names like log_dir instead of d turn the script into self-documenting code.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: Bash011Config

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: Bash011Config,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (Bash011Config): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    min_len = config.min_variable_name_length or 3
    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.match(r"^\s*([A-Za-z_][A-Za-z0-9_]*)=", line)
        if not match:
            continue
        name = match[1]
        if name.isupper() or name in {"i", "j", "k"}:
            continue
        if len(name) < min_len:
            violations.append(
                self.build_violation(
                    config,
                    contains=name,
                    location=Location(line=idx, column=1),
                    suggestion="Use descriptive variable names.",
                ),
            )
            break
    return violations

BashSignalHandlingDetector

BashSignalHandlingDetector()

Bases: ViolationDetector[BashSignalHandlingConfig], LocationHelperMixin

Detect scripts that lack trap handlers for cleanup on exit or signals.

Scripts that create temporary files, acquire locks, or start background processes must clean up on EXIT, INT, and TERM signals. Without a trap handler, an interrupted script leaves stale temp files, dangling lock files, or orphaned child processes.

Note

Add trap cleanup EXIT near the top of the script to guarantee that cleanup runs regardless of how the script terminates.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashSignalHandlingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashSignalHandlingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashSignalHandlingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "trap " not in context.code:
        return [
            self.build_violation(
                config,
                contains="trap",
                location=Location(line=1, column=1),
                suggestion="Add trap handlers for cleanup and signals.",
            ),
        ]
    return []

BashArrayUsageDetector

BashArrayUsageDetector()

Bases: ViolationDetector[BashArrayUsageConfig], LocationHelperMixin

Detect IFS-based string splitting used instead of proper Bash arrays.

Setting IFS to split a string into tokens and iterating over unquoted $var is fragile — it breaks when values contain the delimiter character and does not preserve empty fields. This detector flags IFS= assignments and for x in $var patterns, recommending Bash arrays with "${array[@]}" iteration instead.

Note

Bash arrays handle whitespace-containing elements correctly and should be preferred over IFS-splitting for list-like data.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashArrayUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashArrayUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashArrayUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"\bIFS=|\bfor\s+\w+\s+in\s+\$", context.code):
        return [
            self.build_violation(
                config,
                contains="array",
                location=Location(line=1, column=1),
                suggestion='Prefer arrays and iterate with "${array[@]}".',
            ),
        ]
    return []

BashUsageInfoDetector

BashUsageInfoDetector()

Bases: ViolationDetector[BashUsageInfoConfig], LocationHelperMixin

Detect scripts lacking a usage function or --help/-h flag.

A script without built-in help forces users to read the source code to understand its arguments and options. This detector checks for the presence of a usage keyword or --help/-h string and flags scripts that provide neither.

Note

Even minimal scripts benefit from a usage() function that prints expected arguments and exits with a non-zero code on misuse.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: BashUsageInfoConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/bash/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BashUsageInfoConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (BashUsageInfoConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if not re.search(r"\busage\b", context.code) and not re.search(
        r"--help|-h",
        context.code,
    ):
        return [
            self.build_violation(
                config,
                contains="usage",
                location=Location(line=1, column=1),
                suggestion="Provide a usage function or -h/--help flag.",
            ),
        ]
    return []

C++

mcp_zen_of_languages.languages.cpp.detectors

Zen-rule detectors for C++ code quality, safety, and modern idiom checks.

Each detector implements the Strategy pattern as a ViolationDetector subclass, targeting a specific C++ anti-pattern. Modern C++ (C++11 through C++23) provides RAII, smart pointers, constexpr, range-based loops, and std::optional to replace error-prone C-era patterns; these detectors enforce that transition.

See Also

CppAnalyzer: Template Method analyzer that orchestrates these detectors.

Classes

CppSmartPointerDetector

CppSmartPointerDetector()

Bases: ViolationDetector[CppSmartPointerConfig], LocationHelperMixin

Flags raw new/delete usage where smart pointers should be used.

Manual new/delete is the leading cause of memory leaks, dangling pointers, and double-free vulnerabilities in C++ code. std::unique_ptr and std::shared_ptr provide deterministic, exception-safe ownership semantics that eliminate entire categories of runtime errors with zero overhead (for unique_ptr) or minimal overhead (for shared_ptr).

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp_smart_pointers' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the smart-pointer rule.

TYPE: str

Functions
detect
detect(context, config)

Flag lines containing raw new or delete expressions.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Smart-pointer detection configuration.

TYPE: CppSmartPointerConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppSmartPointerConfig,
) -> list[Violation]:
    """Flag lines containing raw ``new`` or ``delete`` expressions.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppSmartPointerConfig): Smart-pointer detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="new",
            location=Location(line=idx, column=1),
            suggestion=("Prefer smart pointers and RAII over manual new/delete."),
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"\bnew\b", line) or re.search(r"\bdelete\b", line)
    ]
    return violations

CppNullptrDetector

CppNullptrDetector()

Bases: ViolationDetector[CppNullptrConfig], LocationHelperMixin

Flags legacy NULL macro usage instead of the type-safe nullptr literal.

The NULL macro is a C holdover typically defined as 0 or (void*)0, which participates in integer overload resolution and can silently select the wrong function overload. nullptr introduced in C++11 has its own type (std::nullptr_t) that only converts to pointer types, preventing subtle overload-resolution bugs.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp_nullptr' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the nullptr rule.

TYPE: str

Functions
detect
detect(context, config)

Flag lines that reference the NULL macro.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Nullptr detection configuration.

TYPE: CppNullptrConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppNullptrConfig,
) -> list[Violation]:
    """Flag lines that reference the ``NULL`` macro.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppNullptrConfig): Nullptr detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="nullptr",
            location=Location(line=idx, column=1),
            suggestion="Use nullptr instead of NULL/0.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"\bNULL\b", line)
    ]
    return violations

CppRaiiDetector

CppRaiiDetector()

Bases: ViolationDetector[CppRaiiConfig], LocationHelperMixin

Detects manual resource management that should use RAII wrappers.

RAII (Resource Acquisition Is Initialization) is the cornerstone of safe C++ resource management. Raw new/delete, malloc/free calls bypass destructor-based cleanup, leaving resources leaked when exceptions unwind the stack or early returns skip cleanup code. Using RAII wrappers like std::unique_ptr, std::lock_guard, or custom scoped handles ensures deterministic release regardless of control flow.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-001' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the RAII rule.

TYPE: str

Functions
detect
detect(context, config)

Flag lines with new/delete/malloc/free that bypass RAII.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

RAII detection configuration.

TYPE: CppRaiiConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppRaiiConfig,
) -> list[Violation]:
    """Flag lines with ``new``/``delete``/``malloc``/``free`` that bypass RAII.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppRaiiConfig): RAII detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="RAII",
            location=Location(line=idx, column=1),
            suggestion="Prefer RAII wrappers instead of manual resource control.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"\bnew\b|\bdelete\b|malloc\(|free\(", line)
    ]
    return violations

CppAutoDetector

CppAutoDetector()

Bases: ViolationDetector[CppAutoConfig], LocationHelperMixin

Suggests auto type deduction where explicit std:: types add verbosity.

When the right-hand side of an assignment makes the type obvious (e.g., auto it = container.begin()), spelling out the full type clutters code without adding information. auto reduces visual noise, prevents narrowing-conversion surprises, and makes refactoring safer because the variable type tracks the expression automatically.

Note

Lines already containing auto are skipped; only verbose std:: assignments are flagged.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-003' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the auto-deduction rule.

TYPE: str

Functions
detect
detect(context, config)

Flag assignments with explicit std:: types that could use auto.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Auto-deduction detection configuration.

TYPE: CppAutoConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppAutoConfig,
) -> list[Violation]:
    """Flag assignments with explicit ``std::`` types that could use ``auto``.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppAutoConfig): Auto-deduction detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        if "auto " in line:
            continue
        if "std::" in line and "=" in line:
            violations.append(
                self.build_violation(
                    config,
                    contains="auto",
                    location=Location(line=idx, column=1),
                    suggestion="Use auto for obvious type deduction.",
                ),
            )
    return violations

CppRangeForDetector

CppRangeForDetector()

Bases: ViolationDetector[CppRangeForConfig], LocationHelperMixin

Flags iterator-based for loops that should use range-based for.

C++11 range-based for loops (for (auto& x : container)) eliminate off-by-one errors, remove boilerplate .begin()/.end() calls, and express intent more clearly than manual iterator management. They also compose better with structured bindings (C++17) for map iteration.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-005' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the range-for rule.

TYPE: str

Functions
detect
detect(context, config)

Flag for loops using explicit .begin()/.end() iterators.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Range-for detection configuration.

TYPE: CppRangeForConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppRangeForConfig,
) -> list[Violation]:
    """Flag ``for`` loops using explicit ``.begin()``/``.end()`` iterators.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppRangeForConfig): Range-for detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="range-for",
            location=Location(line=idx, column=1),
            suggestion="Prefer range-based for loops for iteration.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "for" in line and (".begin()" in line or ".end()" in line)
    ]
    return violations

CppManualAllocationDetector

CppManualAllocationDetector()

Bases: ViolationDetector[CppManualAllocationConfig], LocationHelperMixin

Detects C-style heap allocation (malloc/free, new[]/delete[]).

Manual heap allocation requires exact pairing of allocate/deallocate calls and is inherently exception-unsafe. Standard containers (std::vector, std::array) and smart pointers manage memory automatically, provide bounds checking in debug builds, and integrate with move semantics for efficient transfers. C-style allocation should be reserved for FFI boundaries or custom allocator implementations.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-006' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the manual-allocation rule.

TYPE: str

Functions
detect
detect(context, config)

Flag malloc/free and array new[]/delete[] usage.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Manual-allocation detection configuration.

TYPE: CppManualAllocationConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppManualAllocationConfig,
) -> list[Violation]:
    """Flag ``malloc``/``free`` and array ``new[]``/``delete[]`` usage.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppManualAllocationConfig): Manual-allocation detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="allocation",
            location=Location(line=idx, column=1),
            suggestion="Use standard containers or smart pointers.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"malloc\(|free\(|new\s+\w+\s*\[|delete\s*\[", line)
    ]
    return violations

CppConstCorrectnessDetector

CppConstCorrectnessDetector()

Bases: ViolationDetector[CppConstCorrectnessConfig], LocationHelperMixin

Flags non-const references where const qualification is appropriate.

Const correctness is a compile-time contract that prevents accidental mutation. Passing objects by non-const reference when the function does not modify them misleads readers, prevents the compiler from optimising, and can mask bugs where mutation was unintended. Marking parameters and locals const wherever possible is a core C++ Core Guideline.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-007' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the const-correctness rule.

TYPE: str

Functions
detect
detect(context, config)

Flag reference parameters and variables missing const qualification.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Const-correctness detection configuration.

TYPE: CppConstCorrectnessConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppConstCorrectnessConfig,
) -> list[Violation]:
    """Flag reference parameters and variables missing ``const`` qualification.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppConstCorrectnessConfig): Const-correctness detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="const",
            location=Location(line=idx, column=1),
            suggestion="Mark references as const where applicable.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "&" in line and "const" not in line
    ]
    return violations

CppCStyleCastDetector

CppCStyleCastDetector()

Bases: ViolationDetector[CppCStyleCastConfig], LocationHelperMixin

Detects C-style casts that should use static_cast/dynamic_cast.

C-style casts ((int)x) silently combine const_cast, static_cast, reinterpret_cast, and even removing access protection in a single opaque syntax. C++-style named casts make the programmer's intent explicit, are searchable in code, and trigger compiler diagnostics when the conversion is unsafe.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-008' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the C-style-cast rule.

TYPE: str

Functions
detect
detect(context, config)

Flag C-style cast syntax on lines not already using named casts.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

C-style-cast detection configuration.

TYPE: CppCStyleCastConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppCStyleCastConfig,
) -> list[Violation]:
    """Flag C-style cast syntax on lines not already using named casts.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppCStyleCastConfig): C-style-cast detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        if "static_cast" in line or "dynamic_cast" in line:
            continue
        if re.search(r"\([A-Za-z_][A-Za-z0-9_:<>]*\)\s*\w", line):
            violations.append(
                self.build_violation(
                    config,
                    contains="cast",
                    location=Location(line=idx, column=1),
                    suggestion="Use C++-style casts (static_cast, dynamic_cast).",
                ),
            )
    return violations

CppRuleOfFiveDetector

CppRuleOfFiveDetector()

Bases: ViolationDetector[CppRuleOfFiveConfig], LocationHelperMixin

Flags classes with destructors but missing copy/move special members.

The Rule of Five states that if a class defines any of the destructor, copy constructor, copy assignment, move constructor, or move assignment, it should explicitly define or default all five. Failing to do so risks shallow copies of owned resources, double-free on destruction, and silently deleted move operations that degrade performance.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-009' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the Rule-of-Five rule.

TYPE: str

Functions
detect
detect(context, config)

Flag classes with a destructor but no operator= definition.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Rule-of-Five detection configuration.

TYPE: CppRuleOfFiveConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppRuleOfFiveConfig,
) -> list[Violation]:
    """Flag classes with a destructor but no ``operator=`` definition.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppRuleOfFiveConfig): Rule-of-Five detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"~\w+\s*\(", context.code) and "operator=" not in context.code:
        return [
            self.build_violation(
                config,
                contains="rule of five",
                suggestion="Define or default copy/move operations consistently.",
            ),
        ]
    return []

CppMoveDetector

CppMoveDetector()

Bases: ViolationDetector[CppMoveConfig], LocationHelperMixin

Flags rvalue references (&&) without corresponding std::move.

Move semantics (C++11) enable zero-copy ownership transfer, but the benefit is only realised when std::move is used to cast lvalues to rvalue references. Code that accepts && parameters but copies instead of moving wastes the performance advantage and misleads readers about ownership intent.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-010' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the move-semantics rule.

TYPE: str

Functions
detect
detect(context, config)

Flag code with && references but no std::move usage.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Move-semantics detection configuration.

TYPE: CppMoveConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppMoveConfig,
) -> list[Violation]:
    """Flag code with ``&&`` references but no ``std::move`` usage.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppMoveConfig): Move-semantics detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "&&" in context.code and "std::move" not in context.code:
        return [
            self.build_violation(
                config,
                contains="std::move",
                suggestion="Use std::move when transferring ownership.",
            ),
        ]
    return []

CppAvoidGlobalsDetector

CppAvoidGlobalsDetector()

Bases: ViolationDetector[CppAvoidGlobalsConfig], LocationHelperMixin

Detects mutable global and file-scope static/extern variables.

Mutable globals introduce hidden coupling between translation units, create data races in multi-threaded programs, and make unit testing nearly impossible because state persists across test cases. The C++ Core Guidelines recommend scoped state managed through function parameters or dependency injection instead.

Note

static_assert lines are excluded because they are compile-time checks, not mutable state.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-011' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the avoid-globals rule.

TYPE: str

Functions
detect
detect(context, config)

Flag file-scope static or extern declarations (excluding static_assert).

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Global-avoidance detection configuration.

TYPE: CppAvoidGlobalsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppAvoidGlobalsConfig,
) -> list[Violation]:
    """Flag file-scope ``static`` or ``extern`` declarations (excluding ``static_assert``).

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppAvoidGlobalsConfig): Global-avoidance detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="global",
            location=Location(line=idx, column=1),
            suggestion="Avoid mutable globals; use scoped state.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.match(r"\s*(static|extern)\s+", line) and "static_assert" not in line
    ]
    return violations

CppOverrideFinalDetector

CppOverrideFinalDetector()

Bases: ViolationDetector[CppOverrideFinalConfig], LocationHelperMixin

Flags virtual overrides missing the override or final specifier.

Without override, a typo in a virtual method signature silently creates a new function instead of overriding the base class version, a bug that is invisible until runtime. override (C++11) turns this into a compile-time error. final additionally prevents further overriding, enabling devirtualisation optimisations.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-012' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the override/final rule.

TYPE: str

Functions
detect
detect(context, config)

Flag virtual methods lacking override or final specifiers.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Override/final detection configuration.

TYPE: CppOverrideFinalConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppOverrideFinalConfig,
) -> list[Violation]:
    """Flag ``virtual`` methods lacking ``override`` or ``final`` specifiers.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppOverrideFinalConfig): Override/final detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="override",
            location=Location(line=idx, column=1),
            suggestion="Add override/final to virtual overrides.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "virtual" in line and "override" not in line and "final" not in line
    ]
    return violations

CppOptionalDetector

CppOptionalDetector()

Bases: ViolationDetector[CppOptionalConfig], LocationHelperMixin

Suggests std::optional over nullable raw pointers for optional values.

Using raw pointers to represent "maybe a value" conflates ownership, nullability, and optionality into a single ambiguous type. std::optional (C++17) is a value-semantic wrapper that makes the "no value" state explicit in the type system, prevents null-pointer dereferences at compile time (with value()), and avoids heap allocation entirely.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cpp-013' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the std::optional rule.

TYPE: str

Functions
detect
detect(context, config)

Flag pointer declarations where std::optional would express intent better.

PARAMETER DESCRIPTION
context

Analysis context with C++ source text.

TYPE: AnalysisContext

config

Optional detection configuration.

TYPE: CppOptionalConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/cpp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CppOptionalConfig,
) -> list[Violation]:
    """Flag pointer declarations where ``std::optional`` would express intent better.

    Args:
        context (AnalysisContext): Analysis context with C++ source text.
        config (CppOptionalConfig): Optional detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if (
        re.search(r"\b\w+\s*\*\s*\w+", context.code)
        and "std::optional" not in context.code
    ):
        return [
            self.build_violation(
                config,
                contains="optional",
                suggestion="Prefer std::optional over nullable pointers.",
            ),
        ]
    return []

C

mcp_zen_of_languages.languages.csharp.detectors

Zen-rule detectors for C# code quality, .NET idiom, and type-safety checks.

Each detector implements the Strategy pattern as a ViolationDetector subclass, targeting a specific C# anti-pattern. Modern C# (8-12) provides nullable reference types, pattern matching, records, and async/await to replace legacy patterns; these detectors enforce that adoption.

See Also

CSharpAnalyzer: Template Method analyzer that orchestrates these detectors.

Classes

CSharpAsyncAwaitDetector

CSharpAsyncAwaitDetector()

Bases: ViolationDetector[CSharpAsyncAwaitConfig], LocationHelperMixin

Flags synchronous blocking on tasks via .Result or .Wait().

Calling .Result or .Wait() on a Task blocks the calling thread and can deadlock in UI or ASP.NET synchronization contexts where the continuation needs the same thread that is now blocked. Using await instead yields the thread back to the pool, preventing deadlocks and keeping the application responsive under load.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'csharp_async_await' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the async/await rule.

TYPE: str

Functions
detect
detect(context, config)

Flag lines that block on tasks with .Result or .Wait().

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Async/await detection configuration.

TYPE: CSharpAsyncAwaitConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpAsyncAwaitConfig,
) -> list[Violation]:
    """Flag lines that block on tasks with ``.Result`` or ``.Wait()``.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpAsyncAwaitConfig): Async/await detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="async",
            location=Location(line=idx, column=1),
            suggestion="Avoid blocking on tasks; use async/await.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if ".Result" in line or ".Wait()" in line
    ]
    return violations

CSharpStringInterpolationDetector

CSharpStringInterpolationDetector()

Bases: ViolationDetector[CSharpStringInterpolationConfig], LocationHelperMixin

Flags String.Format usage where string interpolation is cleaner.

String.Format requires positional index placeholders ({0}, {1}) that are error-prone and hard to read. C# 6+ string interpolation ($"Hello {name}") embeds expressions inline, is checked at compile time, and allocates fewer intermediate strings on the managed heap.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'csharp_string_interpolation' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the string-interpolation rule.

TYPE: str

Functions
detect
detect(context, config)

Flag calls to String.Format that should use interpolation.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

String-interpolation detection configuration.

TYPE: CSharpStringInterpolationConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpStringInterpolationConfig,
) -> list[Violation]:
    """Flag calls to ``String.Format`` that should use interpolation.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpStringInterpolationConfig): String-interpolation detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="String.Format",
            location=Location(line=idx, column=1),
            suggestion=(
                'Use string interpolation ($"...") instead of String.Format.'
            ),
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "String.Format" in line
    ]
    return violations

CSharpNullableDetector

CSharpNullableDetector()

Bases: ViolationDetector[CSharpNullableConfig], LocationHelperMixin

Detects files missing #nullable enable for nullable reference types.

C# 8 nullable reference types turn NullReferenceException from a runtime surprise into a compile-time warning. Without #nullable enable, the compiler cannot distinguish nullable from non-nullable references, leaving the most common .NET exception class unguarded and forcing defensive null checks throughout the codebase.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-001' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the nullable-reference-types rule.

TYPE: str

Functions
detect
detect(context, config)

Flag files that do not contain a #nullable enable directive.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Nullable detection configuration.

TYPE: CSharpNullableConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpNullableConfig,
) -> list[Violation]:
    """Flag files that do not contain a ``#nullable enable`` directive.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpNullableConfig): Nullable detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "#nullable enable" not in context.code:
        return [
            self.build_violation(
                config,
                contains="nullable",
                suggestion="Enable nullable reference types with #nullable enable.",
            ),
        ]
    return []

CSharpExpressionBodiedDetector

CSharpExpressionBodiedDetector()

Bases: ViolationDetector[CSharpExpressionBodiedConfig], LocationHelperMixin

Flags verbose property getters that should use expression-bodied members.

Expression-bodied members (=> expression;) introduced in C# 6 eliminate brace-and-return boilerplate for single-expression getters and methods, reducing visual noise and making the class surface area immediately scannable.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-002' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the expression-bodied-member rule.

TYPE: str

Functions
detect
detect(context, config)

Flag get { return ... } patterns that could be expression-bodied.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Expression-bodied detection configuration.

TYPE: CSharpExpressionBodiedConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpExpressionBodiedConfig,
) -> list[Violation]:
    """Flag ``get { return ... }`` patterns that could be expression-bodied.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpExpressionBodiedConfig): Expression-bodied detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    return next(
        (
            [
                self.build_violation(
                    config,
                    contains="expression-bodied",
                    location=Location(line=idx, column=1),
                    suggestion="Use expression-bodied members for simple getters.",
                ),
            ]
            for idx, line in enumerate(context.code.splitlines(), start=1)
            if re.search(r"\bget\s*\{\s*return", line)
        ),
        [],
    )

CSharpVarDetector

CSharpVarDetector()

Bases: ViolationDetector[CSharpVarConfig], LocationHelperMixin

Flags explicit primitive type declarations where var improves readability.

When the right-hand side of an assignment makes the type obvious (e.g., new List<string>()), repeating List<string> on the left adds redundancy without clarity. var reduces line length and keeps the focus on the variable name and its initial value, following the .NET coding convention for obvious-type assignments.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-003' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the var-usage rule.

TYPE: str

Functions
detect
detect(context, config)

Flag assignments with explicit primitive types that could use var.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Var-usage detection configuration.

TYPE: CSharpVarConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpVarConfig,
) -> list[Violation]:
    """Flag assignments with explicit primitive types that could use ``var``.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpVarConfig): Var-usage detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    pattern = re.compile(r"\b(int|string|bool|double|float|decimal)\s+\w+\s*=")
    violations.extend(
        self.build_violation(
            config,
            contains="var",
            location=Location(line=idx, column=1),
            suggestion="Use var when the type is obvious.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if pattern.search(line)
    )
    return violations

CSharpPatternMatchingDetector

CSharpPatternMatchingDetector()

Bases: ViolationDetector[CSharpPatternMatchingConfig], LocationHelperMixin

Suggests pattern matching (is/switch expressions) over explicit casts.

C# 7+ pattern matching combines type testing and variable declaration in a single expression, eliminating the need for separate is checks followed by casts. This reduces boxing for value types and prevents InvalidCastException by making the type check and extraction atomic.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-005' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the pattern-matching rule.

TYPE: str

Functions
detect
detect(context, config)

Flag is type checks that could leverage pattern matching.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Pattern-matching detection configuration.

TYPE: CSharpPatternMatchingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpPatternMatchingConfig,
) -> list[Violation]:
    """Flag ``is`` type checks that could leverage pattern matching.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpPatternMatchingConfig): Pattern-matching detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    return next(
        (
            [
                self.build_violation(
                    config,
                    contains="pattern",
                    location=Location(line=idx, column=1),
                    suggestion="Use pattern matching (is/expression) instead of casts.",
                ),
            ]
            for idx, line in enumerate(context.code.splitlines(), start=1)
            if "is " in line and "switch" not in line
        ),
        [],
    )

CSharpCollectionExpressionDetector

CSharpCollectionExpressionDetector()

Bases: ViolationDetector[CSharpCollectionExpressionConfig], LocationHelperMixin

Flags verbose new List or new T[] where collection expressions work.

C# 12 collection expressions ([a, b, c]) provide a concise, target-typed syntax for initialising lists, arrays, and spans. They reduce boilerplate, improve readability, and allow the compiler to choose the optimal backing storage based on the target type.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-007' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the collection-expression rule.

TYPE: str

Functions
detect
detect(context, config)

Flag new List or new T[] initialisations that could use [].

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Collection-expression detection configuration.

TYPE: CSharpCollectionExpressionConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpCollectionExpressionConfig,
) -> list[Violation]:
    """Flag ``new List`` or ``new T[]`` initialisations that could use ``[]``.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpCollectionExpressionConfig): Collection-expression detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    return next(
        (
            [
                self.build_violation(
                    config,
                    contains="collection",
                    location=Location(line=idx, column=1),
                    suggestion="Prefer collection expressions ([]) for simple lists.",
                ),
            ]
            for idx, line in enumerate(context.code.splitlines(), start=1)
            if re.search(r"new\s+List|new\s+\w+\[\]", line)
        ),
        [],
    )

CSharpNamingConventionDetector

CSharpNamingConventionDetector()

Bases: ViolationDetector[Cs008Config], LocationHelperMixin

Enforces .NET naming conventions for public and private members.

The .NET Framework Design Guidelines prescribe PascalCase for public members and camelCase (optionally _-prefixed) for private fields. Consistent naming enables developers to infer visibility from the identifier alone, which is critical in large codebases where navigating by convention replaces navigating by access modifiers.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-008' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the naming-convention rule.

TYPE: str

Functions
detect
detect(context, config)

Flag public/private members that violate configured naming styles.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Contains public_naming and private_naming style rules.

TYPE: Cs008Config

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(self, context: AnalysisContext, config: Cs008Config) -> list[Violation]:
    """Flag public/private members that violate configured naming styles.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (Cs008Config): Contains ``public_naming`` and ``private_naming`` style rules.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """

    def matches_style(name: str, style: str) -> bool:
        """Check whether a symbol name conforms to the given casing style.

        Args:
            name (str): Symbol name to validate (e.g., ``myField``, ``MyProperty``).
            style (str): Casing convention to match—``PascalCase`` or ``camelCase``.

        Returns:
            bool: ``True`` when the name matches the expected casing style.
        """
        style_lower = style.lower()
        if "pascal" in style_lower:
            return bool(re.match(r"^[A-Z][A-Za-z0-9]*$", name))
        if "camel" in style_lower:
            return bool(re.match(r"^_?[a-z][A-Za-z0-9]*$", name))
        return True

    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.search(r"\bpublic\s+\w[\w<>,\s]*\s+([A-Za-z_]\w*)", line)
        if match and config.public_naming:
            name = match[1]
            if not matches_style(name, config.public_naming):
                return [
                    self.build_violation(
                        config,
                        contains=name,
                        location=Location(line=idx, column=match.start(1) + 1),
                        suggestion=f"Use {config.public_naming} for public members.",
                    ),
                ]
        match = re.search(r"\bprivate\s+\w[\w<>,\s]*\s+([A-Za-z_]\w*)", line)
        if match and config.private_naming:
            name = match[1]
            if not matches_style(name, config.private_naming):
                return [
                    self.build_violation(
                        config,
                        contains=name,
                        location=Location(line=idx, column=match.start(1) + 1),
                        suggestion=f"Use {config.private_naming} for private members.",
                    ),
                ]
    return []

CSharpDisposableDetector

CSharpDisposableDetector()

Bases: ViolationDetector[CSharpDisposableConfig], LocationHelperMixin

Detects IDisposable resources not wrapped in using statements.

.NET's deterministic disposal pattern requires IDisposable objects (database connections, file handles, HTTP clients) to be wrapped in using blocks or declarations. Without using, the Dispose() call depends on the garbage collector's finaliser queue, leading to resource exhaustion under load—connection pool starvation is the most common symptom.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-009' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the disposable-resource rule.

TYPE: str

Functions
detect
detect(context, config)

Flag code referencing IDisposable/Dispose() without using.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Disposable detection configuration.

TYPE: CSharpDisposableConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpDisposableConfig,
) -> list[Violation]:
    """Flag code referencing ``IDisposable``/``Dispose()`` without ``using``.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpDisposableConfig): Disposable detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if ("IDisposable" in code or "Dispose()" in code) and "using" not in code:
        return [
            self.build_violation(
                config,
                contains="using",
                suggestion="Wrap disposable resources in using statements.",
            ),
        ]
    return []

CSharpMagicNumberDetector

CSharpMagicNumberDetector()

Bases: ViolationDetector[CSharpMagicNumberConfig], LocationHelperMixin

Flags hard-coded numeric literals (magic numbers) in business logic.

Magic numbers embedded in code hide domain intent and make maintenance hazardous—changing a threshold means finding every occurrence of the same literal across the codebase. Named constants (const or static readonly) provide self-documenting, single-source-of-truth values that the JIT compiler can inline just as efficiently.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-010' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the magic-number rule.

TYPE: str

Functions
detect
detect(context, config)

Flag multi-digit numeric literals that should be named constants.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Magic-number detection configuration.

TYPE: CSharpMagicNumberConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpMagicNumberConfig,
) -> list[Violation]:
    """Flag multi-digit numeric literals that should be named constants.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpMagicNumberConfig): Magic-number detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"\b\d{2,}\b", context.code):
        return [
            self.build_violation(
                config,
                contains="magic number",
                suggestion="Replace magic numbers with named constants.",
            ),
        ]
    return []

CSharpLinqDetector

CSharpLinqDetector()

Bases: ViolationDetector[CSharpLinqConfig], LocationHelperMixin

Suggests LINQ methods (Select/Where) over manual foreach loops.

LINQ provides a declarative, composable query syntax that expresses what to compute rather than how to iterate. Replacing imperative foreach accumulation with Select, Where, and Aggregate reduces mutable state, enables deferred execution, and aligns with the functional programming features built into the .NET runtime.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-011' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the LINQ-preference rule.

TYPE: str

Functions
detect
detect(context, config)

Flag foreach loops that lack corresponding LINQ method calls.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

LINQ detection configuration.

TYPE: CSharpLinqConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpLinqConfig,
) -> list[Violation]:
    """Flag ``foreach`` loops that lack corresponding LINQ method calls.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpLinqConfig): LINQ detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if "foreach" in code and ".Select" not in code and ".Where" not in code:
        return [
            self.build_violation(
                config,
                contains="LINQ",
                suggestion="Use LINQ methods like Select/Where for collections.",
            ),
        ]
    return []

CSharpExceptionHandlingDetector

CSharpExceptionHandlingDetector()

Bases: ViolationDetector[CSharpExceptionHandlingConfig], LocationHelperMixin

Flags overly broad catch (Exception) or empty catch blocks.

Catching the base Exception type swallows OutOfMemoryException, StackOverflowException, and other critical failures that should crash the process. Empty catch blocks silently discard errors, making production debugging impossible. Best practice is to catch the most specific exception type and log or re-throw with context.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-012' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the exception-handling rule.

TYPE: str

Functions
detect
detect(context, config)

Flag catch (Exception) and bare catch blocks.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Exception-handling detection configuration.

TYPE: CSharpExceptionHandlingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpExceptionHandlingConfig,
) -> list[Violation]:
    """Flag ``catch (Exception)`` and bare ``catch`` blocks.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpExceptionHandlingConfig): Exception-handling detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if (
        re.search(r"catch\s*\(\s*Exception", context.code)
        or "catch {" in context.code
    ):
        return [
            self.build_violation(
                config,
                contains="catch",
                suggestion="Catch specific exceptions and avoid empty handlers.",
            ),
        ]
    return []

CSharpRecordDetector

CSharpRecordDetector()

Bases: ViolationDetector[CSharpRecordConfig], LocationHelperMixin

Suggests record types for immutable data-transfer objects (DTOs).

C# 9 record types provide value-based equality, immutability via init-only setters, built-in ToString(), and with-expression cloning—all of which must be hand-written for plain class DTOs. Using class with get; set; properties for data carriers wastes boilerplate and invites accidental mutation of shared state.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'cs-013' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the record-type rule.

TYPE: str

Functions
detect
detect(context, config)

Flag class definitions with get; set; that could be records.

PARAMETER DESCRIPTION
context

Analysis context with C# source text.

TYPE: AnalysisContext

config

Record-type detection configuration.

TYPE: CSharpRecordConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/csharp/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CSharpRecordConfig,
) -> list[Violation]:
    """Flag ``class`` definitions with ``get; set;`` that could be records.

    Args:
        context (AnalysisContext): Analysis context with C# source text.
        config (CSharpRecordConfig): Record-type detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if "class " in code and "record " not in code and "get; set;" in code:
        return [
            self.build_violation(
                config,
                contains="record",
                suggestion="Prefer records for immutable DTOs.",
            ),
        ]
    return []

Go

mcp_zen_of_languages.languages.go.detectors

Rule detectors for go code quality and architecture checks.

Classes

GoErrorHandlingDetector

GoErrorHandlingDetector()

Bases: ViolationDetector[GoErrorHandlingConfig]

Flags ignored errors, unchecked err variables, and panic() calls in Go code.

Go's explicit if err != nil pattern is the language's primary safety mechanism — there are no exceptions. Assigning errors to _, calling panic() in library code, or leaving err unchecked silently discards failure information. This detector uses regex to count all three anti-patterns and flags files whose combined total exceeds the configured threshold.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoErrorHandlingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoErrorHandlingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoErrorHandlingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    code = context.code
    counts = {
        "panic": len(re.findall(r"\bpanic\s*\(", code)),
        "ignored": len(re.findall(r"\b_,\s*err\s*:=", code)),
        "unchecked": len(re.findall(r"\berr\s*:=", code)),
    }
    total = counts["panic"] + counts["ignored"] + counts["unchecked"]
    if total > config.max_ignored_errors:
        violations.append(
            self.build_violation(
                config,
                contains="error",
                index=0,
                suggestion=(
                    "Check errors explicitly; avoid panic or ignored errors in "
                    "libraries."
                ),
            ),
        )
    return violations

GoInterfaceSizeDetector

GoInterfaceSizeDetector()

Bases: ViolationDetector[GoInterfaceSizeConfig]

Detects oversized interfaces that violate Go's preference for small, composable contracts.

Go proverb: "The bigger the interface, the weaker the abstraction." Interfaces with many methods are hard to implement, hard to mock in tests, and tightly couple consumers to a single implementation. This detector parses interface bodies via regex, counts non-comment method lines, and flags interfaces that exceed the configured maximum.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoInterfaceSizeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoInterfaceSizeConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoInterfaceSizeConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    if not re.search(r"\binterface\b", context.code):
        return violations
    max_methods = config.max_interface_methods
    for match in re.finditer(
        r"type\s+(\w+)\s+interface\s*\{([\s\S]*?)\}",
        context.code,
    ):
        body = match.group(2)
        methods = [
            line
            for line in body.splitlines()
            if line.strip() and not line.strip().startswith("//")
        ]
        if len(methods) > max_methods:
            violations.append(
                self.build_violation(
                    config,
                    contains="interfaces",
                    index=0,
                    suggestion="Split large interfaces into smaller ones.",
                ),
            )
    return violations

GoContextUsageDetector

GoContextUsageDetector()

Bases: ViolationDetector[GoContextUsageConfig]

Flags code that lacks context.Context for cancellation and deadline propagation.

In Go, context.Context is the standard mechanism for cancellation, timeouts, and request-scoped values across goroutine boundaries. Long-running or network-bound operations without a context parameter cannot be cancelled gracefully. This detector checks whether the source mentions context.Context at all and flags its absence when required by configuration.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoContextUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoContextUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoContextUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    if config.require_context and "context.Context" not in context.code:
        violations.append(
            self.build_violation(
                config,
                contains="context",
                index=0,
                suggestion=(
                    "Pass context.Context to long-running or cancellable "
                    "operations."
                ),
            ),
        )
    return violations

GoDeferUsageDetector

GoDeferUsageDetector()

Bases: ViolationDetector[GoDeferUsageConfig]

Detects defer misuse inside loops and missing defer for resource cleanup.

defer in Go schedules a call to run when the enclosing function returns, making it ideal for releasing resources like file handles and locks. However, defer inside a loop defers until function exit — not loop iteration — causing resource leaks. This detector also scans for .Close() and .Unlock() calls that are not deferred, flagging forgotten cleanup.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoDeferUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoDeferUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoDeferUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    code = context.code
    if config.detect_defer_in_loop and re.search(
        r"for\s+.+\{[\s\S]*?\bdefer\b",
        code,
    ):
        violations.append(
            self.build_violation(
                config,
                contains="defer",
                index=0,
                suggestion=(
                    "Avoid defers inside tight loops; defer outside or manage "
                    "resources explicitly."
                ),
            ),
        )
    if not config.detect_missing_defer:
        return violations
    lines = code.splitlines()
    close_pattern = re.compile(r"\b(\w+(?:\.\w+)*)\.(Close|Unlock)\s*\(\)")
    for idx, line in enumerate(lines, start=1):
        match = close_pattern.search(line)
        if not match:
            continue
        if "defer" in line:
            continue
        prev_line = lines[idx - 2] if idx > 1 else ""
        if "defer" in prev_line:
            continue
        method = match[2]
        contains = "Unlock" if method == "Unlock" else "Close"
        violations.append(
            self.build_violation(
                config,
                contains=contains,
                index=0,
                suggestion="Defer cleanup immediately after acquiring the resource.",
            ),
        )
    return violations

GoNamingConventionDetector

GoNamingConventionDetector()

Bases: ViolationDetector[GoNamingConventionConfig]

Flags overly long variable names that violate Go's brevity conventions.

Go favors short, context-driven names — r for a reader, ctx for a context — because the language's small function scopes make long names redundant. This detector uses a regex to find var declarations with identifiers exceeding 24 characters and suggests shorter, more idiomatic alternatives.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoNamingConventionConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoNamingConventionConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoNamingConventionConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    if not config.detect_long_names:
        return violations
    for _ in re.finditer(r"\bvar\s+(\w{25,})\b", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="variable names",
                index=0,
                suggestion="Use short, contextual variable names in local scopes.",
            ),
        )
        break
    return violations

GoInterfaceReturnDetector

GoInterfaceReturnDetector()

Bases: ViolationDetector[GoInterfaceReturnConfig]

Flags functions that return interface types instead of concrete structs.

Go idiom: "Accept interfaces, return structs." Returning an interface hides the concrete type from callers, preventing them from accessing type-specific methods or embedding the struct. It also makes it harder to discover what a function actually produces. This detector uses a regex to find function signatures that return interface{ and suggests returning concrete types instead.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoInterfaceReturnConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoInterfaceReturnConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoInterfaceReturnConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"func\s+\w+\([^)]*\)\s+interface\s*\{", context.code):
        return [
            self.build_violation(
                config,
                contains="interface",
                suggestion="Accept interfaces, return concrete structs.",
            ),
        ]
    return []

GoZeroValueDetector

GoZeroValueDetector()

Bases: ViolationDetector[GoZeroValueConfig]

Flags New* constructor functions where making the zero value usable would be simpler.

Go's zero-value philosophy means a var x MyStruct should be ready to use without initialization. When a package exports NewFoo() constructors, callers must remember to call them, and forgetting leads to nil-pointer panics. This detector scans for func New* patterns and suggests designing structs so their zero values are valid.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoZeroValueConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoZeroValueConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoZeroValueConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"\bfunc\s+New\w+\b", context.code):
        return [
            self.build_violation(
                config,
                contains="New",
                suggestion="Prefer making zero values usable without constructors.",
            ),
        ]
    return []

GoInterfacePointerDetector

GoInterfacePointerDetector()

Bases: ViolationDetector[GoInterfacePointerConfig]

Detects pointers to interfaces, which are almost always a mistake in Go.

Interfaces in Go are already reference-like values (a type-pointer plus a data-pointer), so *MyInterface adds an unnecessary level of indirection that confuses the type system and prevents interface satisfaction. This detector scans for *<name>Interface and *interface{ patterns via regex.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoInterfacePointerConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoInterfacePointerConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoInterfacePointerConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"\*\w+Interface\b|\*interface\s*\{", context.code):
        return [
            self.build_violation(
                config,
                contains="*interface",
                suggestion="Avoid pointers to interfaces.",
            ),
        ]
    return []

GoGoroutineLeakDetector

GoGoroutineLeakDetector()

Bases: ViolationDetector[GoGoroutineLeakConfig]

Flags goroutines launched without cancellation support and unclosed channels.

Goroutine leaks are among the most insidious Go bugs: a goroutine blocked on a channel or network call with no way to cancel accumulates silently until the process runs out of memory. This detector checks for go func invocations that lack a context.Context cancellation path and make(chan ...) allocations without a corresponding close() call.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoGoroutineLeakConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoGoroutineLeakConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoGoroutineLeakConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    violations: list[Violation] = []
    if "go func" in code and "context.Context" not in code:
        violations.append(
            self.build_violation(
                config,
                contains="goroutine",
                suggestion="Ensure goroutines can terminate (context/cancel).",
            ),
        )
    if re.search(r"make\s*\(\s*chan\b", code) and "close(" not in code:
        violations.append(
            self.build_violation(
                config,
                contains="close",
                suggestion="Close channels to signal completion and avoid leaks.",
            ),
        )
    return violations

GoPackageNamingDetector

GoPackageNamingDetector()

Bases: ViolationDetector[GoPackageNamingConfig]

Flags package names that violate Go's singular, lowercase naming convention.

The Go specification and community style guides require package names to be short, lowercase, singular nouns — no underscores, no mixedCaps, no plurals. A package named utils or string_helpers signals poor cohesion. This detector extracts the package declaration and checks for trailing s or embedded underscores.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoPackageNamingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoPackageNamingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoPackageNamingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if match := re.search(r"^\s*package\s+(\w+)", context.code, re.MULTILINE):
        name = match[1]
        if name.endswith("s") or "_" in name:
            return [
                self.build_violation(
                    config,
                    contains=name,
                    suggestion="Use singular, lowercase package names.",
                ),
            ]
    return []

GoPackageStateDetector

GoPackageStateDetector()

Bases: ViolationDetector[GoPackageStateConfig]

Flags mutable package-level variables that introduce hidden global state.

Package-level var declarations are effectively globals: they create implicit coupling between functions, make testing difficult, and introduce data races in concurrent programs. Go encourages passing dependencies explicitly via function arguments or struct fields. This detector scans for top-level var declarations and flags their presence.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoPackageStateConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoPackageStateConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoPackageStateConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"^\s*var\s+\w+", context.code, re.MULTILINE):
        return [
            self.build_violation(
                config,
                contains="package state",
                suggestion="Avoid mutable package-level state.",
            ),
        ]
    return []

GoInitUsageDetector

GoInitUsageDetector()

Bases: ViolationDetector[GoInitUsageConfig]

Flags func init() usage that hides initialization logic from callers.

Go's init() functions run automatically at package load time, creating invisible side effects that make testing and dependency ordering unpredictable. Explicit initialization via exported functions gives callers control over when and how setup happens. This detector simply checks for the presence of func init( in the source.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: GoInitUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoInitUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (GoInitUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "func init(" in context.code:
        return [
            self.build_violation(
                config,
                contains="init",
                suggestion="Prefer explicit initialization over init().",
            ),
        ]
    return []

GoOrganizeResponsibilityDetector

GoOrganizeResponsibilityDetector()

Bases: ViolationDetector[GoSinglePurposePackageConfig]

Detects catch-all package names like util, common, or helper.

"Each package fulfils a single purpose" — generic package names indicate a grab-bag of unrelated functionality.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect catch-all Go package names.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: GoSinglePurposePackageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoSinglePurposePackageConfig,
) -> list[Violation]:
    """Detect catch-all Go package names.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (GoSinglePurposePackageConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(
        r"^package\s+(util|utils|common|helper|helpers|misc|shared)\b",
        context.code,
        re.MULTILINE,
    ):
        return [
            self.build_violation(
                config,
                contains="package",
                suggestion="Each package should fulfil a single purpose.",
            ),
        ]
    return []

GoEarlyReturnDetector

GoEarlyReturnDetector()

Bases: ViolationDetector[GoEarlyReturnConfig]

Flags err == nil guards that nest the happy path instead of returning early.

Go convention favours returning errors immediately to keep the main logic at the top indentation level.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect err == nil nesting anti-pattern.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: GoEarlyReturnConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoEarlyReturnConfig,
) -> list[Violation]:
    """Detect ``err == nil`` nesting anti-pattern.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (GoEarlyReturnConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(r"if\s+err\s*==\s*nil\s*\{", context.code):
        return [
            self.build_violation(
                config,
                contains="err == nil",
                suggestion="Return early rather than nesting deeply.",
            ),
        ]
    return []

GoEmbeddingDepthDetector

GoEmbeddingDepthDetector()

Bases: ViolationDetector[GoEmbeddingDepthConfig]

Flags structs with too many anonymously embedded types.

Go allows embedding struct types without a field name. Deep embedding chains make the type hierarchy hard to reason about and introduce implicit method promotion conflicts. This detector counts anonymous (embedded) fields inside each struct definition and flags files where any struct exceeds max_embedding_depth.

An anonymous embedded field is a struct field with no explicit name — only a type (e.g. io.Reader or *Base). Named fields such as Name Type are excluded because they follow the \w+ \w+ pattern.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect excessive struct embedding depth.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: GoEmbeddingDepthConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoEmbeddingDepthConfig,
) -> list[Violation]:
    """Detect excessive struct embedding depth.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (GoEmbeddingDepthConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    # Extract lines from top-level struct bodies.  We scan line-by-line
    # between `type X struct {` and the matching `}` at indent level 0,
    # so nested inline struct definitions are naturally excluded.
    in_struct = False
    brace_depth = 0
    struct_lines: list[str] = []
    for line in context.code.splitlines():
        if not in_struct:
            if re.match(
                r"^\s*type\s+\w+(\s*\[[^\]]+\])?\s+struct\s*\{",
                line,
            ):
                in_struct = True
                brace_depth = line.count("{") - line.count("}")
                struct_lines = []
        else:
            brace_depth += line.count("{") - line.count("}")
            if brace_depth <= 0:
                # End of top-level struct body — count embedded fields.
                body = "\n".join(struct_lines)
                named_names = {
                    m.group("name") for m in self._NAMED_RE.finditer(body)
                }
                embedded = [
                    ln
                    for ln in self._EMBEDDED_RE.findall(body)
                    if self._bare_type_name(ln) not in named_names
                ]
                if len(embedded) > config.max_embedding_depth:
                    return [
                        self.build_violation(
                            config,
                            contains="struct",
                            suggestion="Limit embedding depth; prefer explicit composition.",
                        ),
                    ]
                in_struct = False
            elif brace_depth == 1:
                # Top-level struct field lines only (skip nested struct lines).
                struct_lines.append(line)
    return []

GoConcurrencyCallerDetector

GoConcurrencyCallerDetector()

Bases: ViolationDetector[GoConcurrencyCallerConfig]

Flags functions that spawn goroutines internally.

Go proverb: leave concurrency decisions to the caller so that library code remains composable and testable.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect internal goroutine spawning.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: GoConcurrencyCallerConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoConcurrencyCallerConfig,
) -> list[Violation]:
    """Detect internal goroutine spawning.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (GoConcurrencyCallerConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(r"\bgo\s+func\b|\bgo\s+\w+\(", context.code):
        return [
            self.build_violation(
                config,
                contains="go ",
                suggestion="Leave concurrency to the caller.",
            ),
        ]
    return []

GoSimplicityDetector

GoSimplicityDetector()

Bases: ViolationDetector[GoSimplicityConfig]

Flags empty interface usage that weakens type safety.

interface{} (or any) discards compile-time type information. Prefer specific types or small interfaces.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect empty interface usage.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: GoSimplicityConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoSimplicityConfig,
) -> list[Violation]:
    """Detect empty interface usage.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (GoSimplicityConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(r"\binterface\s*\{\s*\}", context.code):
        return [
            self.build_violation(
                config,
                contains="interface{}",
                suggestion="Prefer specific types over empty interfaces; simplicity matters.",
            ),
        ]
    return []

GoTestPresenceDetector

GoTestPresenceDetector()

Bases: ViolationDetector[GoTestPresenceConfig]

Flags exported functions without accompanying test functions.

Every exported API surface should have tests to lock in expected behaviour and prevent regressions.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect exported functions without tests.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: GoTestPresenceConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoTestPresenceConfig,
) -> list[Violation]:
    """Detect exported functions without tests.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (GoTestPresenceConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    has_exported = re.search(r"func\s+[A-Z]", context.code)
    has_tests = re.search(r"func\s+Test", context.code)
    if has_exported and not has_tests:
        return [
            self.build_violation(
                config,
                contains="exported function",
                suggestion="Write tests to lock in API behaviour.",
            ),
        ]
    return []

GoBenchmarkDetector

GoBenchmarkDetector()

Bases: ViolationDetector[GoBenchmarkConfig]

Flags optimisation primitives used without benchmark proof.

sync.Pool and unsafe.Pointer are advanced optimisations that should be justified by benchmark results.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect optimisation without benchmarks.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: GoBenchmarkConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoBenchmarkConfig,
) -> list[Violation]:
    """Detect optimisation without benchmarks.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (GoBenchmarkConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    has_optim = re.search(r"sync\.Pool|unsafe\.Pointer", context.code)
    has_bench = re.search(r"func\s+Benchmark", context.code)
    if has_optim and not has_bench:
        return [
            self.build_violation(
                config,
                contains="optimization",
                suggestion="Prove it's slow with a benchmark before optimizing.",
            ),
        ]
    return []

GoModerationDetector

GoModerationDetector()

Bases: ViolationDetector[GoModerationConfig]

Flags excessive goroutine spawning within a single file.

Moderation is a virtue — too many go statements in one file suggest uncontrolled concurrency that is hard to reason about.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect goroutine proliferation.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: GoModerationConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoModerationConfig,
) -> list[Violation]:
    """Detect goroutine proliferation.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (GoModerationConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    count = len(re.findall(r"\bgo\s+", context.code))
    if count > config.max_goroutine_spawns:
        return [
            self.build_violation(
                config,
                contains="goroutine",
                suggestion="Moderation is a virtue; limit goroutine proliferation.",
            ),
        ]
    return []

GoMaintainabilityDetector

GoMaintainabilityDetector()

Bases: ViolationDetector[GoMaintainabilityConfig]

Flags exported functions missing godoc comments.

Go convention requires every exported symbol to have a comment starting with the symbol name for go doc to render correctly.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect exported functions without godoc comments.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: GoMaintainabilityConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/go/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GoMaintainabilityConfig,
) -> list[Violation]:
    """Detect exported functions without godoc comments.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (GoMaintainabilityConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    lines = context.code.splitlines()
    for idx, line in enumerate(lines):
        if re.match(r"func\s+[A-Z]\w*\(", line):
            prev = lines[idx - 1].strip() if idx > 0 else ""
            if not prev.startswith("//"):
                return [
                    self.build_violation(
                        config,
                        contains="exported function",
                        suggestion="Add godoc comments for exported functions.",
                    ),
                ]
    return []

JavaScript

mcp_zen_of_languages.languages.javascript.detectors

Rule detectors for JavaScript code quality and idiomatic best-practice checks.

Each detector in this module targets a specific JavaScript anti-pattern — from legacy var declarations and loose equality to callback hell and unhandled promise rejections. Detectors scan source lines with regex patterns because no Python-native JavaScript AST is currently integrated.

See Also

JavaScriptAnalyzer: The analyzer that wires these detectors into its pipeline.

Classes

JsCallbackNestingDetector

JsCallbackNestingDetector()

Bases: ViolationDetector[JsCallbackNestingConfig], LocationHelperMixin

Detect deeply nested callbacks that create "callback hell".

JavaScript's event-driven model often leads to pyramids of nested function or => callbacks, making control flow hard to follow and errors easy to swallow. This detector tracks nesting depth by counting callback openings vs. closing braces and flags files that exceed the configured threshold.

Note

Modern code should prefer async/await or chained Promises to keep nesting shallow and readable.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: JsCallbackNestingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsCallbackNestingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (JsCallbackNestingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    max_nesting = config.max_callback_nesting
    code = context.code
    nesting = 0
    max_seen = 0
    for line in code.splitlines():
        if "function" in line or "=>" in line:
            nesting += 1
            max_seen = max(max_seen, nesting)
        if "}" in line:
            nesting = max(nesting - 1, 0)
    if max_seen > max_nesting:
        return [
            self.build_violation(
                config,
                contains="callback",
                suggestion=(
                    "Reduce nested callbacks by using async/await or Promises."
                ),
            ),
        ]
    return []

JsNoVarDetector

JsNoVarDetector()

Bases: ViolationDetector[JsNoVarConfig], LocationHelperMixin

Detect usage of the legacy var keyword for variable declarations.

var has function scope rather than block scope, which leads to subtle hoisting bugs and accidental variable leaks in loops and conditionals. This detector scans every line for the \\bvar\\b pattern and reports each occurrence with its exact line and column position.

Note

const (for immutable bindings) and let (for mutable bindings) are block-scoped and should always be preferred over var.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: JsNoVarConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsNoVarConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (JsNoVarConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="var",
            location=Location(line=idx, column=line.find("var") + 1),
            suggestion="Use const/let instead of var.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"\bvar\b", line)
    ]
    return violations

JsStrictEqualityDetector

JsStrictEqualityDetector()

Bases: ViolationDetector[JsStrictEqualityConfig], LocationHelperMixin

Detect loose equality operators (== / !=) in JavaScript.

JavaScript's abstract equality algorithm performs type coercion before comparison, producing counter-intuitive results such as 0 == "" evaluating to true. This detector scans for == and != while skipping their strict counterparts (=== / !==), reporting the exact column of each offending operator.

Note

Strict equality (=== / !==) avoids implicit coercion and is the standard recommendation in ESLint's eqeqeq rule.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: JsStrictEqualityConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsStrictEqualityConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (JsStrictEqualityConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        if "==" in line or "!=" in line:
            if "===" in line or "!==" in line:
                continue
            if match := re.search(r"(!=|==)", line):
                violations.append(
                    self.build_violation(
                        config,
                        contains="==",
                        location=Location(line=idx, column=match.start() + 1),
                        suggestion="Use === or !== instead of ==/!=.",
                    ),
                )
    return violations

JsAsyncErrorHandlingDetector

JsAsyncErrorHandlingDetector()

Bases: ViolationDetector[JsAsyncErrorHandlingConfig], LocationHelperMixin

Detect async functions and promise chains with missing error handling.

Unhandled promise rejections crash Node.js processes (since v15+) and silently swallow errors in browsers. This detector raises a violation when an async function body contains no try/catch or .catch() call, and when .then() chains lack a trailing .catch() within a four-line look-ahead window.

Note

Every async call path should terminate in a catch clause to prevent unhandled-rejection crashes in production.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: JsAsyncErrorHandlingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsAsyncErrorHandlingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (JsAsyncErrorHandlingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    violations: list[Violation] = []
    if "async " in code and "try" not in code and ".catch" not in code:
        violations.append(
            self.build_violation(
                config,
                contains="catch",
                suggestion="Handle async errors with try/catch or .catch().",
            ),
        )
    lines = code.splitlines()
    for idx, line in enumerate(lines):
        if ".then" not in line:
            continue
        window = "\n".join(lines[idx : idx + 4])
        if ".catch" in window:
            continue
        violations.append(
            self.build_violation(
                config,
                contains="catch",
                suggestion="Always terminate promise chains with .catch().",
            ),
        )
        break
    return violations

JsFunctionLengthDetector

JsFunctionLengthDetector()

Bases: ViolationDetector[JsFunctionLengthConfig], LocationHelperMixin

Detect JavaScript functions that exceed a configurable line-count limit.

Long functions violate the single-responsibility principle and are harder to test, review, and maintain. This detector finds function keyword declarations, counts lines until the closing brace, and flags any that exceed max_function_length.

Note

Arrow functions and method shorthand are not currently matched; the detector focuses on classic function declarations.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: JsFunctionLengthConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsFunctionLengthConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (JsFunctionLengthConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    limit = config.max_function_length
    violations: list[Violation] = []
    lines = context.code.splitlines()
    for idx, line in enumerate(lines, start=1):
        if line.strip().startswith("function "):
            length = 0
            for sub in lines[idx:]:
                if sub.strip().startswith("}"):
                    break
                length += 1
            if length > limit:
                violations.append(
                    self.build_violation(
                        config,
                        contains="function",
                        location=Location(line=idx, column=1),
                        suggestion=f"Keep functions <= {limit} lines.",
                    ),
                )
    return violations

JsGlobalStateDetector

JsGlobalStateDetector()

Bases: ViolationDetector[JsGlobalStateConfig], LocationHelperMixin

Detect direct access to global mutable state via window, globalThis, or global.

Relying on global state creates hidden coupling between modules, makes code non-deterministic, and breaks in environments where the expected global object differs (e.g., window is undefined in Node.js workers). This detector flags lines that reference any of the three common global accessors.

Note

Prefer dependency injection or module-scoped state to keep functions pure and testable.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: JsGlobalStateConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsGlobalStateConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (JsGlobalStateConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="global",
            location=Location(line=idx, column=1),
            suggestion="Avoid global mutable state.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "window." in line or "globalThis." in line or "global." in line
    ]
    return violations

JsModernFeaturesDetector

JsModernFeaturesDetector()

Bases: ViolationDetector[JsModernFeaturesConfig], LocationHelperMixin

Detect opportunities to adopt modern ES6+ language features.

Legacy patterns like anonymous function() expressions, string concatenation with +, and repeated property access without destructuring are harder to read and more error-prone. This detector checks for each pattern independently and suggests arrow functions, template literals, or destructuring as replacements.

Note

All modern browsers and Node.js 14+ support these features natively — there is no reason to avoid them in new code.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: JsModernFeaturesConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsModernFeaturesConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (JsModernFeaturesConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    code = context.code
    if "function(" in code:
        violations.append(
            self.build_violation(
                config,
                contains="arrow functions",
                index=0,
                suggestion="Prefer arrow functions and other modern syntax.",
            ),
        )
    if re.search(r"['\"][^'\"]+['\"]\s*\+|\+\s*['\"][^'\"]+['\"]", code):
        violations.append(
            self.build_violation(
                config,
                contains="template literals",
                index=0,
                suggestion="Use template literals instead of string concatenation.",
            ),
        )
    for line in code.splitlines():
        matches = re.findall(r"\b(\w+)\.\w+", line)
        if any(
            matches.count(name) >= MIN_REPEATED_ACCESS_COUNT
            for name in set(matches)
        ):
            violations.append(
                self.build_violation(
                    config,
                    contains="destructuring",
                    index=0,
                    suggestion="Use object destructuring for repeated property access.",
                ),
            )
            break
    return violations

JsMagicNumbersDetector

JsMagicNumbersDetector()

Bases: ViolationDetector[JsMagicNumbersConfig], LocationHelperMixin

Detect unexplained numeric literals (magic numbers) in JavaScript code.

Magic numbers obscure intent — a reader cannot tell whether 86400 means "seconds in a day" or an unrelated constant. This detector uses a regex to find integer literals ≥ 2 that are not assigned to a named constant, and recommends extracting them into descriptive const declarations.

Note

Common trivial values like 0 and 1 are intentionally excluded from detection to reduce false positives.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: JsMagicNumbersConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsMagicNumbersConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (JsMagicNumbersConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"\b[2-9]\d*\b", context.code):
        return [
            self.build_violation(
                config,
                contains="magic numbers",
                suggestion="Use named constants instead of magic numbers.",
            ),
        ]
    return []

JsInheritanceDepthDetector

JsInheritanceDepthDetector()

Bases: ViolationDetector[Js009Config], LocationHelperMixin

Detect class hierarchies that exceed a maximum inheritance depth.

Deep extends chains tightly couple subclasses to ancestor implementations, making refactoring fragile and debugging painful. This detector builds a parent-child map from class X extends Y declarations, walks each chain, and flags any that exceed the configured max_inheritance_depth.

Note

Composition (injecting behaviour via constructor parameters or mixins) is generally preferred over deep inheritance in JavaScript.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: Js009Config

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(self, context: AnalysisContext, config: Js009Config) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (Js009Config): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    max_depth = config.max_inheritance_depth or 0
    parents: dict[str, str] = {}
    for match in re.finditer(r"class\s+(\w+)\s+extends\s+(\w+)", context.code):
        parents[match.group(1)] = match.group(2)

    def chain_depth(name: str) -> int:
        """Compute the inheritance chain depth for a given class name.

        Args:
            name (str): Class name whose ancestor chain is walked.

        Returns:
            int: Number of ``extends`` hops from *name* to the root class.
        """
        depth = 0
        seen: set[str] = set()
        while name in parents and name not in seen:
            seen.add(name)
            name = parents[name]
            depth += 1
        return depth

    for child in parents:
        if chain_depth(child) > max_depth:
            return [
                self.build_violation(
                    config,
                    contains="extends",
                    suggestion="Prefer composition over deep inheritance chains.",
                ),
            ]
    return []

JsPureFunctionDetector

JsPureFunctionDetector()

Bases: ViolationDetector[JsPureFunctionConfig], LocationHelperMixin

Detect in-place array mutations that break functional programming principles.

Methods like push, pop, splice, shift, and unshift mutate arrays in place, producing side effects that make functions impure and harder to reason about. This detector scans for these method calls and recommends immutable alternatives such as spread syntax, concat, filter, or slice.

Note

Pure functions with immutable data structures are easier to test, cache, and parallelize in both browser and server environments.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: JsPureFunctionConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsPureFunctionConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (JsPureFunctionConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"\b(push|splice|pop|shift|unshift)\s*\(", context.code):
        return [
            self.build_violation(
                config,
                contains="mutation",
                suggestion="Prefer pure functions and immutable operations.",
            ),
        ]
    return []

JsMeaningfulNamesDetector

JsMeaningfulNamesDetector()

Bases: ViolationDetector[Js011Config], LocationHelperMixin

Detect overly short or cryptic identifiers in JavaScript declarations.

Single-character names like x or d outside of loop counters (i, j, k) harm readability and make code searches unreliable. This detector extracts names from const, let, var, function, and class declarations and flags any shorter than min_identifier_length.

Note

Descriptive names serve as inline documentation and reduce the need for explanatory comments.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: Js011Config

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(self, context: AnalysisContext, config: Js011Config) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (Js011Config): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    min_length = config.min_identifier_length or 0
    pattern = re.compile(r"\b(?:const|let|var|function|class)\s+([A-Za-z_]\w*)")
    for idx, line in enumerate(context.code.splitlines(), start=1):
        for match in pattern.finditer(line):
            name = match.group(1)
            if len(name) < min_length and name not in {"i", "j", "k"}:
                return [
                    self.build_violation(
                        config,
                        contains=name,
                        location=Location(line=idx, column=match.start(1) + 1),
                        suggestion="Use clearer, longer identifiers.",
                    ),
                ]
    return []

JsDestructuringDetector

JsDestructuringDetector()

Bases: ViolationDetector[JsDestructuringConfig]

Detect repeated property access on the same object without destructuring.

When three or more property accesses reference the same object name, code becomes verbose and harder to maintain. Destructuring extracts multiple properties in a single statement and makes data dependencies explicit.

Note

const { a, b, c } = obj; is more concise and communicates intent better than three separate obj.x assignments.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector configuration that controls thresholds.

TYPE: JsDestructuringConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsDestructuringConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context: Analysis context containing source text and intermediate
            metrics.
        config: Typed detector configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    matches = re.findall(r"\b(\w+)\.\w+", context.code)
    counts: dict[str, int] = {}
    for m in matches:
        counts[m] = counts.get(m, 0) + 1
    if any(c >= MIN_DESTRUCTURING_ACCESS_COUNT for c in counts.values()):
        return [
            self.build_violation(
                config,
                contains="repeated property access",
                suggestion="Use destructuring for cleaner property assignment.",
            ),
        ]
    return []

JsObjectSpreadDetector

JsObjectSpreadDetector()

Bases: ViolationDetector[JsObjectSpreadConfig]

Detect usage of Object.assign where object spread is preferred.

Object.assign mutates its first argument and is harder to read than the equivalent spread syntax { ...a, ...b }. The spread form is also safer because it always creates a new object.

Note

Object spread is supported in all modern browsers and Node.js 8.3+.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector configuration that controls thresholds.

TYPE: JsObjectSpreadConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsObjectSpreadConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context: Analysis context containing source text and intermediate
            metrics.
        config: Typed detector configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"Object\.assign\s*\(", context.code):
        return [
            self.build_violation(
                config,
                contains="Object.assign",
                suggestion="Prefer object spread {...obj} over Object.assign().",
            ),
        ]
    return []

JsNoWithDetector

JsNoWithDetector()

Bases: ViolationDetector[JsNoWithConfig]

Detect usage of the with statement in JavaScript.

The with statement creates ambiguous scope chains, making it impossible to tell at a glance whether an identifier refers to a property of the with target or an outer variable. It is forbidden in strict mode and should never appear in modern code.

Note

with was deprecated by ES5 strict mode and is a syntax error in ES modules.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector configuration that controls thresholds.

TYPE: JsNoWithConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsNoWithConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context: Analysis context containing source text and intermediate
            metrics.
        config: Typed detector configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"\bwith\s*\(", context.code):
        return [
            self.build_violation(
                config,
                contains="with",
                suggestion="Avoid the with statement; it creates ambiguous scope.",
            ),
        ]
    return []

JsParamCountDetector

JsParamCountDetector()

Bases: ViolationDetector[JsParamCountConfig]

Detect functions with too many parameters.

Functions accepting four or more positional parameters are hard to call correctly — callers must remember argument order, and long signatures impede readability. An options-object parameter collapses the list into a single, self-documenting argument.

Note

function create({ name, age, role }) is clearer than function create(name, age, role, active).

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector configuration that controls thresholds.

TYPE: JsParamCountConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsParamCountConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context: Analysis context containing source text and intermediate
            metrics.
        config: Typed detector configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"function\s+\w+\s*\([^)]*,[^)]*,[^)]*,[^)]*\)", context.code):
        return [
            self.build_violation(
                config,
                contains="parameters",
                suggestion="Limit function parameters; use an options object instead.",
            ),
        ]
    return []

JsNoEvalDetector

JsNoEvalDetector()

Bases: ViolationDetector[JsNoEvalConfig]

Detect usage of eval() or new Function() in JavaScript.

Both eval and the Function constructor execute arbitrary strings as code, opening the door to injection attacks, defeating static analysis, and disabling engine optimisations. There is almost always a safer, more performant alternative.

Note

Content-Security-Policy headers block eval by default in modern browsers — relying on it also limits deployment options.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector configuration that controls thresholds.

TYPE: JsNoEvalConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsNoEvalConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context: Analysis context containing source text and intermediate
            metrics.
        config: Typed detector configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"\beval\s*\(", context.code) or re.search(
        r"new\s+Function\s*\(", context.code
    ):
        return [
            self.build_violation(
                config,
                contains="eval",
                suggestion="Never use eval() or new Function(); they are security risks.",
            ),
        ]
    return []

JsNoArgumentsDetector

JsNoArgumentsDetector()

Bases: ViolationDetector[JsNoArgumentsConfig]

Detect usage of the legacy arguments object in JavaScript.

The arguments object is not a real Array, lacks arrow-function support, and prevents engine optimisations. Rest parameters (...args) provide a true array with full method support and work consistently in both regular and arrow functions.

Note

arguments is unavailable inside arrow functions, so migrating early avoids runtime errors during future refactoring.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector configuration that controls thresholds.

TYPE: JsNoArgumentsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsNoArgumentsConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context: Analysis context containing source text and intermediate
            metrics.
        config: Typed detector configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"\barguments\b", context.code):
        return [
            self.build_violation(
                config,
                contains="arguments",
                suggestion="Use rest parameters (...args) instead of the arguments object.",
            ),
        ]
    return []

JsNoPrototypeMutationDetector

JsNoPrototypeMutationDetector()

Bases: ViolationDetector[JsNoPrototypeMutationConfig]

Detect mutations of built-in object prototypes.

Assigning to Array.prototype, String.prototype, or other built-in prototypes pollutes every instance in the runtime, causing unpredictable interactions between unrelated modules and libraries.

Note

If custom behaviour is needed, use a wrapper function or subclass instead of modifying the shared prototype chain.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector configuration that controls thresholds.

TYPE: JsNoPrototypeMutationConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/javascript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsNoPrototypeMutationConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context: Analysis context containing source text and intermediate
            metrics.
        config: Typed detector configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(
        r"(Array|String|Object|Function|Number|Boolean)\.prototype\.\w+\s*=",
        context.code,
    ):
        return [
            self.build_violation(
                config,
                contains="prototype mutation",
                suggestion="Never mutate built-in prototypes.",
            ),
        ]
    return []

JSON

mcp_zen_of_languages.languages.json.detectors

Detectors for JSON/JSON5 structural and semantic quality checks.

Classes

JsonStrictnessDetector

JsonStrictnessDetector()

Bases: ViolationDetector[JsonStrictnessConfig], LocationHelperMixin

Flag trailing commas when strict JSON output is expected.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

Functions
detect
detect(context, config)

Detect strict-mode trailing comma violations.

Source code in src/mcp_zen_of_languages/languages/json/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsonStrictnessConfig,
) -> list[Violation]:
    """Detect strict-mode trailing comma violations."""
    if config.target_format == "json5" or config.allow_trailing_commas:
        return []
    match = re.search(r",\s*[\]}]", context.code)
    if match:
        line = context.code.count("\n", 0, match.start()) + 1
        return [
            self.build_violation(
                config,
                contains="Trailing",
                location=Location(line=line, column=1),
                suggestion="Remove trailing commas or set target_format=json5.",
            ),
        ]
    return []

JsonSchemaConsistencyDetector

JsonSchemaConsistencyDetector()

Bases: ViolationDetector[JsonSchemaConsistencyConfig], LocationHelperMixin

Detect excessive JSON nesting depth.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

Functions
detect
detect(context, config)

Detect deep nesting beyond the configured threshold.

Source code in src/mcp_zen_of_languages/languages/json/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsonSchemaConsistencyConfig,
) -> list[Violation]:
    """Detect deep nesting beyond the configured threshold."""
    data = _load_json_document(context.code)
    if data is None:
        return []

    def max_depth(node: object, depth: int = 1) -> int:
        if isinstance(node, dict):
            if not node:
                return depth
            return max(max_depth(value, depth + 1) for value in node.values())
        if isinstance(node, list):
            if not node:
                return depth
            return max(max_depth(value, depth + 1) for value in node)
        return depth

    depth = max_depth(data)
    if depth > config.max_depth:
        return [
            self.build_violation(
                config,
                location=Location(line=1, column=1),
                suggestion=f"Reduce nesting depth to {config.max_depth} or below.",
            ),
        ]
    return []

JsonDuplicateKeyDetector

JsonDuplicateKeyDetector()

Bases: ViolationDetector[JsonDuplicateKeyConfig], LocationHelperMixin

Detect duplicate keys in JSON objects.

Duplicate object keys silently override earlier values in most parsers, leading to hard-to-diagnose bugs. This detector uses a parse-time object_pairs_hook to catch duplicates before they are lost.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

Functions
detect
detect(context, config)

Detect duplicate keys while preserving parse-time key order.

Source code in src/mcp_zen_of_languages/languages/json/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsonDuplicateKeyConfig,
) -> list[Violation]:
    """Detect duplicate keys while preserving parse-time key order."""
    duplicates: list[str] = []

    def track_duplicates(pairs: list[tuple[str, object]]) -> dict[str, object]:
        seen: set[str] = set()
        obj: dict[str, object] = {}
        for key, value in pairs:
            if key in seen and key not in duplicates:
                duplicates.append(key)
            seen.add(key)
            obj[key] = value
        return obj

    try:
        json.loads(context.code, object_pairs_hook=track_duplicates)
    except (json.JSONDecodeError, ValueError):
        return []
    if duplicates:
        duplicate_key = duplicates[0]
        return [
            self.build_violation(
                config,
                location=self.find_location_by_substring(
                    context.code,
                    f'"{duplicate_key}"',
                ),
                suggestion="Keep object keys unique to avoid silent overrides.",
            ),
        ]
    return []

JsonMagicStringDetector

JsonMagicStringDetector()

Bases: ViolationDetector[JsonMagicStringConfig], LocationHelperMixin

Detect repeated magic-string values.

Repeated literal strings scattered across a JSON file make maintenance hazardous — updating one instance while missing others leads to inconsistency. This detector flags string values that appear at least min_repetition times and are at least min_length characters long (ignoring semver-like strings such as ^1.2.3).

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

Functions
detect
detect(context, config)

Detect repeated literal strings that behave like magic constants.

Source code in src/mcp_zen_of_languages/languages/json/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsonMagicStringConfig,
) -> list[Violation]:
    """Detect repeated literal strings that behave like magic constants."""
    data = _load_json_document(context.code)
    if data is None:
        return []
    values = [
        value
        for value in _iter_values(data)
        if isinstance(value, str)
        and len(value) >= config.min_length
        and not re.fullmatch(r"[\^~]?\d+\.\d+\.\d+.*", value)
    ]
    if not values:
        return []
    repeated = [
        value
        for value, count in Counter(values).items()
        if count >= config.min_repetition
    ]
    if repeated:
        repeated_value = repeated[0]
        return [
            self.build_violation(
                config,
                location=self.find_location_by_substring(
                    context.code,
                    f'"{repeated_value}"',
                ),
                suggestion=(
                    "Extract repeated string values into shared "
                    "constants or $ref anchors."
                ),
            ),
        ]
    return []

JsonDateFormatDetector

JsonDateFormatDetector()

Bases: ViolationDetector[JsonDateFormatConfig], LocationHelperMixin

Identify date strings that deviate from ISO 8601 formatting.

JSON has no native date type, so dates are encoded as strings. Using locale-dependent formats like MM/DD/YYYY creates ambiguity (is 02/03/2024 the 2nd of March or the 3rd of February?). Prefer YYYY-MM-DD or the full YYYY-MM-DDTHH:MM:SSZ for unambiguous, sortable date representation.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

Functions
detect
detect(context, config)

Detect string values that look like dates but are not ISO 8601.

Source code in src/mcp_zen_of_languages/languages/json/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsonDateFormatConfig,
) -> list[Violation]:
    """Detect string values that look like dates but are not ISO 8601."""
    data = _load_json_document(context.code)
    if data is None:
        return []
    key_fragments = [kf.lower() for kf in config.common_date_keys]
    for key, value in _iter_pairs(data):
        key_lower = key.lower()
        is_date_key = any(frag in key_lower for frag in key_fragments)
        is_non_iso = bool(_NON_ISO_DATE_RE.fullmatch(value))
        is_iso = bool(_ISO_DATE_RE.fullmatch(value))
        # Flag explicit non-ISO dates and date-keyed fields that are not ISO.
        if is_non_iso or (is_date_key and value and not is_iso):
            return [
                self.build_violation(
                    config,
                    location=self.find_location_by_substring(
                        context.code,
                        f'"{value}"',
                    ),
                    suggestion=(
                        "Use ISO 8601 format (YYYY-MM-DD or "
                        "YYYY-MM-DDTHH:MM:SSZ) for date strings."
                    ),
                ),
            ]
    return []

JsonNullHandlingDetector

JsonNullHandlingDetector()

Bases: ViolationDetector[JsonNullHandlingConfig], LocationHelperMixin

Report top-level object keys whose values are explicitly null.

Explicit null values in JSON can signal intentional absence or simply forgotten clean-up. At the top level of a configuration document they almost always mean the key should be omitted rather than set to null. This detector flags documents where more than max_top_level_nulls top-level keys carry a null value.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

Functions
detect
detect(context, config)

Detect top-level object keys explicitly set to null.

Source code in src/mcp_zen_of_languages/languages/json/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsonNullHandlingConfig,
) -> list[Violation]:
    """Detect top-level object keys explicitly set to null."""
    data = _load_json_document(context.code)
    if not isinstance(data, dict):
        return []
    null_keys = [k for k, v in data.items() if v is None]
    if len(null_keys) > config.max_top_level_nulls:
        first_null_key = null_keys[0]
        return [
            self.build_violation(
                config,
                location=self.find_location_by_substring(
                    context.code,
                    f'"{first_null_key}"',
                ),
                suggestion=(
                    "Omit top-level keys instead of setting them "
                    "explicitly to null."
                ),
            ),
        ]
    return []

JsonKeyCasingDetector

JsonKeyCasingDetector()

Bases: ViolationDetector[JsonKeyCasingConfig], LocationHelperMixin

Detect mixed key casing at the same object level.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

Functions
detect
detect(context, config)

Detect mixed key casing at the same object level.

Source code in src/mcp_zen_of_languages/languages/json/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsonKeyCasingConfig,
) -> list[Violation]:
    """Detect mixed key casing at the same object level."""
    data = _load_json_document(context.code)
    if data is None:
        return []
    mixed_key = _find_mixed_key(data)
    if mixed_key:
        return [
            self.build_violation(
                config,
                location=self.find_location_by_substring(
                    context.code, f'"{mixed_key}"'
                ),
                suggestion="Use one key naming convention per object level.",
            ),
        ]
    return []

JsonArrayOrderDetector

JsonArrayOrderDetector()

Bases: ViolationDetector[JsonArrayOrderConfig], LocationHelperMixin

Detect oversized inline arrays.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

Functions
detect
detect(context, config)

Detect arrays that exceed the allowed inline size.

Source code in src/mcp_zen_of_languages/languages/json/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsonArrayOrderConfig,
) -> list[Violation]:
    """Detect arrays that exceed the allowed inline size."""
    data = _load_json_document(context.code)
    if data is None:
        return []
    for node in _iter_values(data):
        if isinstance(node, list) and len(node) > config.max_inline_array_size:
            return [
                self.build_violation(
                    config,
                    location=Location(line=1, column=1),
                    suggestion=(
                        "Move large arrays to separate files or reduce inline "
                        f"size to <= {config.max_inline_array_size}."
                    ),
                ),
            ]
    return []

JsonNullSprawlDetector

JsonNullSprawlDetector()

Bases: ViolationDetector[JsonNullSprawlConfig], LocationHelperMixin

Detect excessive null values across JSON objects/arrays.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

Functions
detect
detect(context, config)

Detect excessive use of null across a document.

Source code in src/mcp_zen_of_languages/languages/json/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: JsonNullSprawlConfig,
) -> list[Violation]:
    """Detect excessive use of null across a document."""
    data = _load_json_document(context.code)
    if data is None:
        return []
    null_count = sum(1 for value in _iter_values(data) if value is None)
    if null_count > config.max_null_values:
        return [
            self.build_violation(
                config,
                location=Location(line=1, column=1),
                suggestion="Omit optional keys instead of spreading null values.",
            ),
        ]
    return []

PowerShell

mcp_zen_of_languages.languages.powershell.detectors

Rule detectors for PowerShell code quality and automation best-practice checks.

Each detector in this module targets a specific PowerShell anti-pattern — from alias usage in scripts and Write-Host misuse to global scope pollution and missing CmdletBinding. Detectors scan source lines with regex patterns because no Python-native PowerShell AST is currently integrated.

See Also

PowerShellAnalyzer: The analyzer that wires these detectors into its pipeline.

Classes

PowerShellApprovedVerbDetector

PowerShellApprovedVerbDetector()

Bases: ViolationDetector[PowerShellApprovedVerbConfig], LocationHelperMixin

Detect function names that use unapproved PowerShell verbs.

PowerShell mandates a standard set of verbs (Get, Set, New, Remove, etc.) for the Verb-Noun naming convention. Using non-standard verbs like Fetch-Data or Grab-Item triggers import warnings, breaks discoverability in Get-Command, and violates the PowerShell module publishing guidelines.

Note

Run Get-Verb in a PowerShell session to see the full list of approved verbs and their expected usage groups.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellApprovedVerbConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellApprovedVerbConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellApprovedVerbConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.search(r"function\s+(\w+)-", line, re.IGNORECASE)
        if match and match[1].lower() not in config.approved_verbs:
            violations.append(
                self.build_violation(
                    config,
                    contains="verb",
                    location=Location(line=idx, column=match.start(1) + 1),
                    suggestion=(
                        "Use approved PowerShell verbs (Get/Set/New/Remove/etc.)."
                    ),
                ),
            )
    return violations

PowerShellErrorHandlingDetector

PowerShellErrorHandlingDetector()

Bases: ViolationDetector[PowerShellErrorHandlingConfig], LocationHelperMixin

Detect scripts that lack any form of error handling.

PowerShell's default Continue error action silently moves past non-terminating errors, allowing scripts to report success despite partial failures. This detector flags scripts that contain no try/catch blocks and no -ErrorAction parameters.

Note

Use $ErrorActionPreference = 'Stop' at the script level or -ErrorAction Stop per cmdlet to promote errors to terminating exceptions that try/catch can handle.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellErrorHandlingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellErrorHandlingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellErrorHandlingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if "try" not in code and "catch" not in code and "-ErrorAction" not in code:
        return [
            self.build_violation(
                config,
                contains="error",
                suggestion="Add try/catch or -ErrorAction to handle errors.",
            ),
        ]
    return []

PowerShellPascalCaseDetector

PowerShellPascalCaseDetector()

Bases: ViolationDetector[PowerShellPascalCaseConfig], LocationHelperMixin

Detect function names that violate PascalCase naming conventions.

PowerShell's ecosystem expects Verb-Noun function names in PascalCase (e.g., Get-ChildItem). Functions named get_data or fetchItems break tab-completion expectations, look foreign alongside built-in cmdlets, and confuse users accustomed to the standard naming pattern.

Note

The regex validates both standalone PascalCase names and hyphenated Verb-Noun pairs to accommodate advanced functions and modules.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellPascalCaseConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellPascalCaseConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellPascalCaseConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        if match := re.search(r"function\s+(\w+)", line, re.IGNORECASE):
            name = match[1]
            if not re.match(r"^[A-Z][A-Za-z0-9]*(-[A-Z][A-Za-z0-9]*)?$", name):
                violations.append(
                    self.build_violation(
                        config,
                        contains="PascalCase",
                        location=Location(line=idx, column=match.start(1) + 1),
                        suggestion="Use PascalCase for function names.",
                    ),
                )
    return violations

PowerShellCmdletBindingDetector

PowerShellCmdletBindingDetector()

Bases: ViolationDetector[PowerShellCmdletBindingConfig], LocationHelperMixin

Detect advanced functions missing [CmdletBinding()] and param().

Without [CmdletBinding()], a function cannot participate in the common-parameter ecosystem (-Verbose, -Debug, -ErrorAction, -WhatIf). Scripts that define functions but omit the attribute lose access to PowerShell's built-in safety and diagnostics features.

Note

[CmdletBinding()] paired with a param() block is the minimum requirement for production-quality advanced functions.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellCmdletBindingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellCmdletBindingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellCmdletBindingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if "function" not in code:
        return []
    if "CmdletBinding" not in code or "param(" not in code:
        return [
            self.build_violation(
                config,
                contains="CmdletBinding",
                suggestion="Add [CmdletBinding()] and a param() block.",
            ),
        ]
    return []

PowerShellVerboseDebugDetector

PowerShellVerboseDebugDetector()

Bases: ViolationDetector[PowerShellVerboseDebugConfig], LocationHelperMixin

Detect Write-Host calls that should use Write-Verbose or Write-Debug.

Write-Host writes directly to the console host, bypassing PowerShell's output streams. Its output cannot be captured, redirected, or suppressed — making scripts unusable in automated pipelines, remoting sessions, and CI/CD environments. This detector flags every Write-Host occurrence.

Note

Use Write-Verbose for operational messages, Write-Debug for developer diagnostics, and Write-Output for pipeline data.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellVerboseDebugConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellVerboseDebugConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellVerboseDebugConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="Write-Host",
            location=Location(line=idx, column=line.find("Write-Host") + 1),
            suggestion=("Use Write-Verbose or Write-Debug for logging output."),
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "Write-Host" in line
    ]
    return violations

PowerShellPositionalParamsDetector

PowerShellPositionalParamsDetector()

Bases: ViolationDetector[PowerShellPositionalParamsConfig], LocationHelperMixin

Detect reliance on $args for positional parameter access.

Using the automatic $args variable instead of a typed param() block sacrifices type validation, tab completion, mandatory-parameter enforcement, and pipeline binding. This detector scans for $args references and recommends named parameters.

Note

Define explicit [Parameter()] attributes with types and validation to make functions self-documenting and IDE-friendly.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellPositionalParamsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellPositionalParamsConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellPositionalParamsConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="$args",
            location=Location(line=idx, column=line.find("$args") + 1),
            suggestion="Prefer named parameters over positional arguments.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "$args" in line
    ]
    return violations

PowerShellPipelineUsageDetector

PowerShellPipelineUsageDetector()

Bases: ViolationDetector[PowerShellPipelineUsageConfig], LocationHelperMixin

Detect ForEach-Object or foreach loops that should use pipelines.

PowerShell's pipeline streams objects one at a time, enabling memory- efficient processing of large datasets. Explicit foreach loops without a pipeline accumulate entire collections in memory and miss the composability benefits of chaining cmdlets with |.

Note

Pipeline-aware code like Get-Process | Where-Object CPU -gt 50 is both more idiomatic and more memory-efficient than loop-based equivalents.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellPipelineUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellPipelineUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellPipelineUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if "|" in code:
        return []
    if re.search(r"\bForEach-Object\b", code, re.IGNORECASE) or re.search(
        r"\bforeach\b",
        code,
        re.IGNORECASE,
    ):
        return [
            self.build_violation(
                config,
                contains="pipeline",
                suggestion="Prefer pipeline operations for object processing.",
            ),
        ]
    return []

PowerShellShouldProcessDetector

PowerShellShouldProcessDetector()

Bases: ViolationDetector[PowerShellShouldProcessConfig], LocationHelperMixin

Detect destructive cmdlet verbs missing SupportsShouldProcess.

Functions that Remove, Set, Stop, Clear, Restart, Disable, or Enable resources should declare [CmdletBinding(SupportsShouldProcess)] so that callers can pass -WhatIf for dry-run confirmation and -Confirm for interactive safety. This detector flags destructive verbs without the attribute.

Note

Always call $PSCmdlet.ShouldProcess() before performing the destructive action to honour -WhatIf and -Confirm flags.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellShouldProcessConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellShouldProcessConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellShouldProcessConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if "SupportsShouldProcess" in code:
        return []
    if re.search(r"\b(Remove|Set|Stop|Clear|Restart|Disable|Enable)-", code):
        return [
            self.build_violation(
                config,
                contains="SupportsShouldProcess",
                suggestion="Add [CmdletBinding(SupportsShouldProcess)] for safety.",
            ),
        ]
    return []

PowerShellSplattingDetector

PowerShellSplattingDetector()

Bases: ViolationDetector[PowerShellSplattingConfig], LocationHelperMixin

Detect cmdlet calls with many inline parameters that should use splatting.

Lines passing four or more -Parameter Value pairs become hard to read, impossible to diff cleanly, and error-prone to maintain. Splatting (@params) moves parameters into a hashtable variable, improving readability and enabling parameter reuse. This detector counts - prefixed tokens per line, skipping lines already using @.

Note

Splatting also simplifies conditional parameter inclusion by letting you build the hashtable dynamically before the call.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellSplattingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellSplattingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellSplattingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        if "@" in line:
            continue
        param_count = len(re.findall(r"\s-\w+", line))
        if param_count >= MAX_INLINE_PARAMS:
            violations.append(
                self.build_violation(
                    config,
                    contains="splatting",
                    location=Location(line=idx, column=1),
                    suggestion="Use splatting for long parameter lists.",
                ),
            )
    return violations

PowerShellParameterValidationDetector

PowerShellParameterValidationDetector()

Bases: ViolationDetector[PowerShellParameterValidationConfig], LocationHelperMixin

Detect param() blocks that lack [Validate*] attributes.

PowerShell's validation attributes ([ValidateNotNullOrEmpty()], [ValidateRange()], [ValidateSet()], etc.) enforce input constraints before the function body runs, producing clear error messages without manual guard clauses. This detector flags param() blocks that omit all validation attributes.

Note

Declarative validation is preferred over manual if checks because it integrates with Get-Help and IDE tooling.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellParameterValidationConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellParameterValidationConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellParameterValidationConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if "param(" in code and "[Validate" not in code:
        return [
            self.build_violation(
                config,
                contains="Validate",
                suggestion="Add [Validate*] attributes for parameters.",
            ),
        ]
    return []

PowerShellCommentHelpDetector

PowerShellCommentHelpDetector()

Bases: ViolationDetector[PowerShellCommentHelpConfig], LocationHelperMixin

Detect functions missing comment-based help with .SYNOPSIS.

PowerShell's Get-Help system relies on structured comment blocks containing .SYNOPSIS, .DESCRIPTION, .PARAMETER, and .EXAMPLE sections. Without them, users cannot discover how to use a function without reading its source code. This detector flags the absence of .SYNOPSIS in the file.

Note

Comment-based help also enables -? and tab-completion of parameter descriptions in the console.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellCommentHelpConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellCommentHelpConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellCommentHelpConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if ".SYNOPSIS" not in context.code:
        return [
            self.build_violation(
                config,
                contains=".SYNOPSIS",
                suggestion="Add comment-based help with .SYNOPSIS and examples.",
            ),
        ]
    return []

PowerShellAliasUsageDetector

PowerShellAliasUsageDetector()

Bases: ViolationDetector[PowerShellAliasUsageConfig], LocationHelperMixin

Detect built-in aliases (gci, ls, %, ?) used in scripts.

Aliases like gci, ls, dir, cat, %, and ? vary across platforms (ls maps to Get-ChildItem on Windows but to /bin/ls on Linux) and are not guaranteed to exist in constrained environments like JEA endpoints. This detector scans for common alias tokens and recommends full cmdlet names for portability.

Note

Aliases are fine for interactive sessions but should never appear in shared scripts, modules, or CI/CD automation.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellAliasUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellAliasUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellAliasUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    alias_pattern = re.compile(r"(?<!\w)(gci|ls|dir|cat|%|\?)(?!\w)")
    for idx, line in enumerate(context.code.splitlines(), start=1):
        if match := alias_pattern.search(line):
            violations.append(
                self.build_violation(
                    config,
                    contains=match[1],
                    location=Location(line=idx, column=match.start(1) + 1),
                    suggestion="Use full cmdlet names instead of aliases.",
                ),
            )
    return violations

PowerShellReturnObjectsDetector

PowerShellReturnObjectsDetector()

Bases: ViolationDetector[PowerShellReturnObjectsConfig], LocationHelperMixin

Detect functions that return formatted text instead of objects.

Using Format-Table or Out-String inside a function bakes a specific display format into the output, preventing downstream cmdlets from filtering, sorting, or exporting the data. PowerShell functions should return rich objects and let the caller choose the presentation format.

Note

Reserve Format-* cmdlets for the final display step in the console, never inside reusable functions or modules.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellReturnObjectsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellReturnObjectsConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellReturnObjectsConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    return next(
        (
            [
                self.build_violation(
                    config,
                    contains=token,
                    suggestion="Return objects instead of formatted text.",
                ),
            ]
            for token in ("Format-Table", "Out-String")
            if token in context.code
        ),
        [],
    )

PowerShellScopeUsageDetector

PowerShellScopeUsageDetector()

Bases: ViolationDetector[PowerShellScopeUsageConfig], LocationHelperMixin

Detect explicit $global: and $script: scope modifiers.

Accessing $global: or $script: variables creates hidden coupling between functions, makes testing difficult (state leaks between test runs), and can introduce race conditions in parallel execution. This detector flags any use of these scope prefixes.

Note

Prefer passing state through parameters and return values to keep functions self-contained and testable in isolation.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellScopeUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellScopeUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellScopeUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "$global:" in context.code or "$script:" in context.code:
        return [
            self.build_violation(
                config,
                contains="scope",
                suggestion="Be explicit and minimize scope usage.",
            ),
        ]
    return []

PowerShellNullHandlingDetector

PowerShellNullHandlingDetector()

Bases: ViolationDetector[PowerShellNullHandlingConfig], LocationHelperMixin

Detect functions and param blocks that never check for $null.

PowerShell treats $null differently from empty strings and empty collections, and cmdlets can return $null unexpectedly when no objects match a filter. Functions that process pipeline input or optional parameters without $null guards risk NullReference errors at runtime. This detector flags scripts containing function or param() declarations with no $null check.

Note

Use if ($null -ne $value) (with $null on the left) to avoid PowerShell's counter-intuitive collection comparison behaviour.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: PowerShellNullHandlingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/powershell/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PowerShellNullHandlingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (PowerShellNullHandlingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if ("function" in code or "param(" in code) and "$null" not in code:
        return [
            self.build_violation(
                config,
                contains="$null",
                suggestion="Add explicit $null checks for safety.",
            ),
        ]
    return []

Python

mcp_zen_of_languages.languages.python.detectors

Python-specific violation detectors implementing the Strategy pattern.

Each detector class encapsulates a single zen-principle check against Python source code. Detectors are instantiated by the registry, wired into a DetectionPipeline, and executed during PythonAnalyzer.analyze().

Detectors fall into two categories:

  • Syntactic detectors — operate directly on source lines or the stdlib ast tree (e.g. StarImportDetector, BareExceptDetector).
  • Metric-gated detectors — rely on pre-computed metrics stored in AnalysisContext (e.g. CyclomaticComplexityDetector reads context.cyclomatic_summary).

Classes

StarImportDetector

StarImportDetector()

Bases: ViolationDetector[StarImportConfig], LocationHelperMixin

Detect wildcard from X import * statements that pollute the module namespace.

Star imports pull every public name from the target module into the current namespace, making it impossible to tell where a name originated from by reading the source alone. They also defeat static analysis tools and IDE auto-complete, and create subtle bugs when two star-imported modules export the same name.

Implements the "Namespaces are one honking great idea" zen principle: explicit imports keep namespaces clean and traceable.

The detector scans raw source lines with a regex rather than walking the AST, because import * is a lexical pattern that is faster to match textually and does not require a successful parse.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "star_imports" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Scan source lines for from X import * patterns.

Each matching line produces a violation pinpointed to the import keyword column so that editors can jump straight to the offending statement.

PARAMETER DESCRIPTION
context

Analysis context carrying the source text to scan.

TYPE: AnalysisContext

config

Star-import detector thresholds and rule metadata.

TYPE: StarImportConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per wildcard import found.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: StarImportConfig,
) -> list[Violation]:
    """Scan source lines for ``from X import *`` patterns.

    Each matching line produces a violation pinpointed to the ``import``
    keyword column so that editors can jump straight to the offending
    statement.

    Args:
        context (AnalysisContext): Analysis context carrying the source text to scan.
        config (StarImportConfig): Star-import detector thresholds and rule metadata.

    Returns:
        list[Violation]: One violation per wildcard import found.
    """
    violations: list[Violation] = []
    message = config.select_violation_message(index=3)
    for i, line in enumerate(context.code.splitlines(), start=1):
        if re.match(r"^\s*from\s+\S+\s+import\s+\*", line):
            loc = Location(line=i, column=line.find("import") + 1)
            violations.append(
                Violation(
                    principle=config.principle
                    or config.principle_id
                    or config.type,
                    severity=config.severity or 4,
                    message=message,
                    location=loc,
                    suggestion=(
                        "Import explicit names to avoid namespace pollution."
                    ),
                ),
            )
    return violations

BareExceptDetector

BareExceptDetector()

Bases: ViolationDetector[BareExceptConfig], LocationHelperMixin

Detect bare except: clauses and silently swallowed exceptions.

A bare except: catches everything — including KeyboardInterrupt and SystemExit — making it nearly impossible to interrupt or terminate the process cleanly. Empty handlers (except SomeError: pass) are equally dangerous because they hide real failures and turn bugs into silent data corruption.

Implements the "Errors should never pass silently" zen principle: exceptions must be caught specifically and handled meaningfully.

Detection works on raw source lines using regex matching, covering three patterns: bare except:, inline except X: pass, and multi-line except X: followed by a pass/... body.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "bare_except" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Scan source lines for bare excepts and empty exception handlers.

Three patterns are checked in order for each line:

  1. except: with no exception type.
  2. Inline except SomeError: pass or except SomeError: ....
  3. except SomeError: on one line followed by pass/... on the next.
PARAMETER DESCRIPTION
context

Analysis context with the source code to inspect.

TYPE: AnalysisContext

config

Bare-except detector thresholds and rule metadata.

TYPE: BareExceptConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per offending except clause.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: BareExceptConfig,
) -> list[Violation]:
    """Scan source lines for bare excepts and empty exception handlers.

    Three patterns are checked in order for each line:

    1. ``except:`` with no exception type.
    2. Inline ``except SomeError: pass`` or ``except SomeError: ...``.
    3. ``except SomeError:`` on one line followed by ``pass``/``...`` on
       the next.

    Args:
        context (AnalysisContext): Analysis context with the source code to inspect.
        config (BareExceptConfig): Bare-except detector thresholds and rule metadata.

    Returns:
        list[Violation]: One violation per offending ``except`` clause.
    """
    violations: list[Violation] = []
    lines = context.code.splitlines()
    for i, line in enumerate(lines, start=1):
        stripped = line.strip()
        if stripped == "except:" or stripped.startswith("except: "):
            loc = Location(line=i, column=line.find("except") + 1)
            violations.append(
                Violation(
                    principle=config.principle
                    or config.principle_id
                    or config.type,
                    severity=config.severity or 5,
                    message=config.select_violation_message(
                        contains="Bare",
                        index=0,
                    ),
                    location=loc,
                    suggestion=(
                        "Catch specific exceptions or re-raise after logging."
                    ),
                ),
            )
            continue
        if re.match(
            r"except\s+\w+(?:\s+as\s+\w+)?\s*:\s*(pass|\.\.\.)\s*$",
            stripped,
        ):
            loc = Location(line=i, column=line.find("except") + 1)
            violations.append(
                Violation(
                    principle=config.principle
                    or config.principle_id
                    or config.type,
                    severity=config.severity or 5,
                    message=config.select_violation_message(
                        contains="Empty",
                        index=0,
                    ),
                    location=loc,
                    suggestion=(
                        "Handle the exception or re-raise; avoid empty except blocks."
                    ),
                ),
            )
            continue
        if re.match(r"except\s+\w+(?:\s+as\s+\w+)?\s*:\s*$", stripped):
            next_line = lines[i] if i < len(lines) else ""
            if next_line.strip() in {"pass", "..."}:
                loc = Location(line=i, column=line.find("except") + 1)
                violations.append(
                    Violation(
                        principle=config.principle
                        or config.principle_id
                        or config.type,
                        severity=config.severity or 5,
                        message=config.select_violation_message(
                            contains="Empty",
                            index=0,
                        ),
                        location=loc,
                        suggestion=(
                            "Handle the exception or re-raise; avoid empty except blocks."
                        ),
                    ),
                )
    return violations

MagicNumberDetector

MagicNumberDetector()

Bases: ViolationDetector[MagicNumberConfig], LocationHelperMixin

Detect excessive use of unexplained numeric literals (magic numbers).

Numeric literals scattered through code obscure intent — a reader seeing if retries > 3 cannot tell whether 3 is an arbitrary guess, a business rule, or a protocol limit. Named constants (MAX_RETRIES = 3) make the code self-documenting and centralise change points.

Implements the "Readability counts" zen principle: every value should communicate its purpose through a descriptive name.

The detector regex-scans each line for integers ≥ 2 and non-integer floats, skipping comments, blank lines, and ALL_CAPS = … constant assignments. A violation fires only when the total count exceeds the configured max_magic_numbers threshold.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "magic_number" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Count numeric literals across non-trivial lines and flag when too many.

Lines that are blank, comments, or ALL_CAPS constant assignments are excluded. The location of the first match is reported to guide the developer to the most likely starting point for refactoring.

PARAMETER DESCRIPTION
context

Analysis context carrying the source text.

TYPE: AnalysisContext

config

Magic-number detector thresholds (max_magic_numbers).

TYPE: MagicNumberConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: At most one violation when the count exceeds the configured threshold.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: MagicNumberConfig,
) -> list[Violation]:
    """Count numeric literals across non-trivial lines and flag when too many.

    Lines that are blank, comments, or ``ALL_CAPS`` constant assignments
    are excluded.  The location of the *first* match is reported to guide
    the developer to the most likely starting point for refactoring.

    Args:
        context (AnalysisContext): Analysis context carrying the source text.
        config (MagicNumberConfig): Magic-number detector thresholds (``max_magic_numbers``).

    Returns:
        list[Violation]: At most one violation when the count exceeds the
            configured threshold.
    """
    violations: list[Violation] = []
    pattern = re.compile(r"\b(?:[2-9]\d*|1\.\d+)\b")
    count = 0
    first_match: tuple[int, int] | None = None
    for idx, line in enumerate(context.code.splitlines(), start=1):
        stripped = line.strip()
        if not stripped or stripped.startswith("#"):
            continue
        if re.match(r"^[A-Z][A-Z0-9_]*\s*=", stripped):
            continue
        for match in pattern.finditer(line):
            count += 1
            if first_match is None:
                first_match = (idx, match.start() + 1)
    if count > config.max_magic_numbers:
        location = (
            Location(line=first_match[0], column=first_match[1])
            if first_match
            else None
        )
        violations.append(
            self.build_violation(
                config,
                contains="Magic numbers",
                index=0,
                location=location,
                suggestion="Use named constants instead of magic numbers.",
            ),
        )
    return violations

ComplexOneLinersDetector

ComplexOneLinersDetector()

Bases: ViolationDetector[ComplexOneLinersConfig], LocationHelperMixin

Detect overly dense one-liner expressions that sacrifice readability.

Deeply nested comprehensions and long ternary chains pack too much logic into a single line, making code hard to debug and impossible to set breakpoints inside. Splitting them into named intermediate steps improves clarity without sacrificing performance.

Implements the "Simple is better than complex" zen principle: favour straightforward multi-line code over clever one-liners.

Two heuristics are applied per line:

  1. Count of for keywords exceeding max_for_clauses flags nested comprehensions.
  2. Lines longer than max_line_length containing both if and else flag complex ternary expressions.
Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "complex_one_liners" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Scan each line for nested comprehensions or complex ternary chains.

Blank lines and comments are skipped. Each offending line produces exactly one violation, choosing the most specific message variant (comprehension vs. generic one-liner).

PARAMETER DESCRIPTION
context

Analysis context carrying the source text.

TYPE: AnalysisContext

config

One-liner detector thresholds (max_for_clauses, max_line_length).

TYPE: ComplexOneLinersConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per line that exceeds the complexity heuristics.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: ComplexOneLinersConfig,
) -> list[Violation]:
    """Scan each line for nested comprehensions or complex ternary chains.

    Blank lines and comments are skipped.  Each offending line produces
    exactly one violation, choosing the most specific message variant
    (comprehension vs. generic one-liner).

    Args:
        context (AnalysisContext): Analysis context carrying the source text.
        config (ComplexOneLinersConfig): One-liner detector thresholds (``max_for_clauses``,
            ``max_line_length``).

    Returns:
        list[Violation]: One violation per line that exceeds the
            complexity heuristics.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        stripped = line.strip()
        if not stripped or stripped.startswith("#"):
            continue
        for_count = len(re.findall(r"\bfor\b", line))
        if for_count > config.max_for_clauses:
            violations.append(
                self.build_violation(
                    config,
                    contains="comprehensions",
                    index=0,
                    location=Location(line=idx, column=1),
                    suggestion="Split nested comprehensions into named steps.",
                ),
            )
            continue
        if (
            len(line) > config.max_line_length
            and " if " in line
            and " else " in line
        ):
            violations.append(
                self.build_violation(
                    config,
                    contains="Complex one-liners",
                    index=0,
                    location=Location(line=idx, column=1),
                    suggestion="Break complex expressions into multiple lines.",
                ),
            )
    return violations

ContextManagerDetector

ContextManagerDetector()

Bases: ViolationDetector[ContextManagerConfig], LocationHelperMixin

Detect open() calls not wrapped in a with context manager.

File handles opened without a context manager risk resource leaks if an exception occurs before .close() is called. The with statement guarantees cleanup even under error conditions.

Implements the "Explicit is better than implicit" zen principle: resource lifetime should be governed by a visible scope, not by garbage collection timing.

Detection walks the stdlib ast tree looking for Call nodes whose function name is open. For each match, a surrounding snippet is checked for with open to avoid false positives on properly managed handles.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "context_manager" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Walk the AST for open() calls and verify with wrapping.

For each open() call node, a small surrounding snippet (±2 lines) is checked for with open. This avoids false positives on handles that are already managed by a context manager.

PARAMETER DESCRIPTION
context

Analysis context with source text and (optionally) a pre-parsed AST.

TYPE: AnalysisContext

config

Context-manager detector thresholds and rule metadata.

TYPE: ContextManagerConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per open() call that is not wrapped in a with block.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: ContextManagerConfig,
) -> list[Violation]:
    """Walk the AST for ``open()`` calls and verify ``with`` wrapping.

    For each ``open()`` call node, a small surrounding snippet (±2 lines)
    is checked for ``with open``.  This avoids false positives on handles
    that are already managed by a context manager.

    Args:
        context (AnalysisContext): Analysis context with source text and (optionally) a
            pre-parsed AST.
        config (ContextManagerConfig): Context-manager detector thresholds and rule metadata.

    Returns:
        list[Violation]: One violation per ``open()`` call that is not
            wrapped in a ``with`` block.
    """
    violations: list[Violation] = []
    message = config.select_violation_message(contains="context managers", index=2)
    try:
        tree = ast.parse(context.code)
    except SyntaxError:
        return violations

    for node in ast.walk(tree):
        if isinstance(node, ast.Call):
            func = node.func
            func_name = None
            if isinstance(func, ast.Name):
                func_name = func.id
            elif isinstance(func, ast.Attribute):
                func_name = func.attr

            if func_name == "open":
                lineno = getattr(node, "lineno", None)
                col = getattr(node, "col_offset", None)
                if lineno is not None:
                    loc = Location(line=lineno, column=(col or 0) + 1)
                    lines = context.code.splitlines()
                    start = max(0, lineno - 3)
                    end = min(len(lines), lineno + 2)
                    snippet = "\n".join(lines[start:end])
                    prev_line = (
                        lines[lineno - 2]
                        if lineno >= MIN_LINE_FOR_PREV_LOOKUP
                        else ""
                    )
                    if (
                        "with open" not in snippet
                        and not prev_line.strip().startswith("with")
                    ):
                        violations.append(
                            Violation(
                                principle=config.principle
                                or config.principle_id
                                or config.type,
                                severity=config.severity or 4,
                                message=message,
                                location=loc,
                                suggestion=(
                                    "Use 'with open(...) as f' to ensure proper resource cleanup."
                                ),
                            ),
                        )
    return violations

DocstringDetector

DocstringDetector()

Bases: ViolationDetector[DocstringConfig], LocationHelperMixin

Detect top-level functions and classes missing a docstring.

Public APIs without docstrings force consumers to read source code to understand behaviour, parameter expectations, and return semantics. Even a one-line docstring dramatically improves discoverability and IDE tooltip support.

Implements the "Readability counts" zen principle: every public interface should document its contract.

Detection uses ast.iter_child_nodes on the module root so that only module-level (top-level) definitions are checked — private helpers nested inside other functions are intentionally excluded.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "docstrings" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Parse the module AST and flag top-level defs lacking a docstring.

Iterates only immediate children of the module node via ast.iter_child_nodes. FunctionDef and ClassDef nodes are checked with ast.get_docstring; classes receive a higher severity because they typically represent broader public contracts.

PARAMETER DESCRIPTION
context

Analysis context with source text to inspect.

TYPE: AnalysisContext

config

Docstring detector thresholds and rule metadata.

TYPE: DocstringConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per undocumented top-level function or class.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: DocstringConfig,
) -> list[Violation]:
    """Parse the module AST and flag top-level defs lacking a docstring.

    Iterates only immediate children of the module node via
    ``ast.iter_child_nodes``.  ``FunctionDef`` and ``ClassDef`` nodes are
    checked with ``ast.get_docstring``; classes receive a higher severity
    because they typically represent broader public contracts.

    Args:
        context (AnalysisContext): Analysis context with source text to inspect.
        config (DocstringConfig): Docstring detector thresholds and rule metadata.

    Returns:
        list[Violation]: One violation per undocumented top-level
            function or class.
    """
    violations: list[Violation] = []
    message = config.select_violation_message(
        contains="Missing docstrings",
        index=3,
    )
    try:
        tree = ast.parse(context.code)
    except SyntaxError:
        return violations

    for node in ast.iter_child_nodes(tree):
        if isinstance(node, ast.FunctionDef):
            if ast.get_docstring(node) is None:
                loc = self.find_location_by_substring(
                    context.code,
                    f"def {node.name}",
                )
                violations.append(
                    Violation(
                        principle=config.principle
                        or config.principle_id
                        or config.type,
                        severity=config.severity or 3,
                        message=message,
                        location=loc,
                        suggestion=(
                            "Add a brief docstring describing purpose and args."
                        ),
                    ),
                )
        elif isinstance(node, ast.ClassDef) and ast.get_docstring(node) is None:
            loc = self.find_location_by_substring(
                context.code,
                f"class {node.name}",
            )
            violations.append(
                Violation(
                    principle=config.principle
                    or config.principle_id
                    or config.type,
                    severity=config.severity or 4,
                    message=message,
                    location=loc,
                    suggestion=("Add class docstring describing responsibilities."),
                ),
            )
    return violations

LineLengthDetector

LineLengthDetector()

Bases: ViolationDetector[LineLengthConfig], LocationHelperMixin

Detect source lines that exceed a configured character limit.

Overly long lines force horizontal scrolling in editors, break side-by- side diffs in code review, and often signal that a statement is doing too much at once. PEP 8 recommends 79 characters; most modern projects settle on 88-120.

Implements the "Beautiful is better than ugly" zen principle: consistent line length produces a visually uniform codebase.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "line_length" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Iterate source lines and emit a violation for each exceeding max_line_length.

The violation location column is set to max_len + 1 so that editors highlight exactly where the overflow begins.

PARAMETER DESCRIPTION
context

Analysis context carrying the source text.

TYPE: AnalysisContext

config

Line-length detector thresholds (max_line_length).

TYPE: LineLengthConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per over-long line.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: LineLengthConfig,
) -> list[Violation]:
    """Iterate source lines and emit a violation for each exceeding ``max_line_length``.

    The violation location column is set to ``max_len + 1`` so that
    editors highlight exactly where the overflow begins.

    Args:
        context (AnalysisContext): Analysis context carrying the source text.
        config (LineLengthConfig): Line-length detector thresholds (``max_line_length``).

    Returns:
        list[Violation]: One violation per over-long line.
    """
    violations: list[Violation] = []
    max_len = config.max_line_length
    principle = config.principle or config.principle_id or config.type
    severity = config.severity or 2
    message = config.select_violation_message(contains="whitespace", index=2)

    for i, line in enumerate(context.code.splitlines(), start=1):
        if len(line) > max_len:
            loc = Location(line=i, column=max_len + 1)
            violations.append(
                Violation(
                    principle=principle,
                    severity=severity,
                    message=message,
                    location=loc,
                    suggestion=(
                        f"Wrap or refactor to keep line <= {max_len} characters."
                    ),
                ),
            )
    return violations

ClassSizeDetector

ClassSizeDetector()

Bases: ViolationDetector[ClassSizeConfig], LocationHelperMixin

Detect classes whose line count exceeds the configured maximum.

Classes that grow beyond a few hundred lines tend to accumulate unrelated responsibilities, making them hard to understand, test, and extend. Splitting oversized classes into smaller, cohesive units improves modularity and keeps each unit within a developer's working memory.

Implements the "Simple is better than complex" zen principle: small classes with clear responsibility boundaries are easier to reason about.

Detection walks the AST for ClassDef nodes and measures each class by the span from its lineno to the lineno of its last body statement.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "class_size" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Walk the AST and flag classes whose line span exceeds max_class_length.

Falls back to ast.parse when the pre-built context.ast_tree is unavailable or not a stdlib ast.AST.

PARAMETER DESCRIPTION
context

Analysis context with source text and parsed tree.

TYPE: AnalysisContext

config

Class-size detector thresholds (max_class_length).

TYPE: ClassSizeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per oversized class.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: ClassSizeConfig,
) -> list[Violation]:
    """Walk the AST and flag classes whose line span exceeds ``max_class_length``.

    Falls back to ``ast.parse`` when the pre-built ``context.ast_tree``
    is unavailable or not a stdlib ``ast.AST``.

    Args:
        context (AnalysisContext): Analysis context with source text and parsed tree.
        config (ClassSizeConfig): Class-size detector thresholds (``max_class_length``).

    Returns:
        list[Violation]: One violation per oversized class.
    """
    violations: list[Violation] = []
    max_lines = config.max_class_length
    principle = config.principle or config.principle_id or config.type
    severity = config.severity or 5
    message = config.select_violation_message(contains="Classes longer", index=1)

    ast_root = None
    try:
        ast_root = (
            context.ast_tree.tree
            if isinstance(context.ast_tree, ParserResult)
            else context.ast_tree
        )
    except AttributeError:
        ast_root = context.ast_tree

    if not isinstance(ast_root, ast.AST):
        try:
            ast_root = ast.parse(context.code)
        except SyntaxError:
            return violations

    for node in ast.walk(ast_root):
        if isinstance(node, ast.ClassDef):
            start = getattr(node, "lineno", None)
            end = None
            if node.body:
                last = node.body[-1]
                end = getattr(last, "lineno", None)
            if start is None or end is None:
                continue

            length = end - start + 1
            if length > max_lines:
                loc = self.ast_node_to_location(context.ast_tree, node)
                violations.append(
                    Violation(
                        principle=principle,
                        severity=severity,
                        message=message,
                        location=loc,
                        suggestion="Split large classes into smaller cohesive units.",
                    ),
                )

    return violations

NameStyleDetector

NameStyleDetector()

Bases: ViolationDetector[NameStyleConfig], LocationHelperMixin

Detect function and variable names that violate Python's snake_case convention.

PEP 8 mandates snake_case for functions and variables. Mixing camelCase or other styles within a Python module confuses readers and clashes with the standard library's consistent naming.

Implements the "There should be one obvious way to do it" zen principle: a single naming convention removes cognitive overhead and keeps style debates out of code review.

The primary path walks the stdlib ast tree to find FunctionDef and Assign nodes. When parsing fails (e.g. partial code snippets), a regex-based heuristic fallback extracts def and assignment names directly from source text.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "name_style" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Walk the AST for non-snake_case function and variable names.

FunctionDef nodes and Assign targets are checked against a snake_case regex. ALL_CAPS constant assignments are intentionally skipped. Tuple/list unpacking targets are flattened before checking.

Falls back to _heuristic_detect when the AST cannot be built.

PARAMETER DESCRIPTION
context

Analysis context with source text and parsed tree.

TYPE: AnalysisContext

config

Name-style detector thresholds and rule metadata.

TYPE: NameStyleConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per non-conforming name.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(  # noqa: C901, PLR0912
    self,
    context: AnalysisContext,
    config: NameStyleConfig,
) -> list[Violation]:
    """Walk the AST for non-snake_case function and variable names.

    ``FunctionDef`` nodes and ``Assign`` targets are checked against a
    ``snake_case`` regex.  ``ALL_CAPS`` constant assignments are
    intentionally skipped.  Tuple/list unpacking targets are flattened
    before checking.

    Falls back to ``_heuristic_detect`` when the AST cannot be built.

    Args:
        context (AnalysisContext): Analysis context with source text and parsed tree.
        config (NameStyleConfig): Name-style detector thresholds and rule metadata.

    Returns:
        list[Violation]: One violation per non-conforming name.
    """
    violations: list[Violation] = []

    tree = None
    try:
        if context.ast_tree is not None:
            maybe_tree = getattr(context.ast_tree, "tree", context.ast_tree)
            if isinstance(maybe_tree, ast.AST):
                tree = maybe_tree
            else:
                tree = getattr(maybe_tree, "tree", None)
                if tree is None:
                    tree = ast.parse(context.code)
        else:
            tree = ast.parse(context.code)
    except (AttributeError, SyntaxError):
        return self._heuristic_detect(context, config)

    principle = config.principle or config.principle_id or config.type
    severity = config.severity or 3
    message = config.select_violation_message(index=1)
    for node in ast.walk(tree):
        if isinstance(node, ast.FunctionDef) and not self._is_snake_case(node.name):
            loc = self.ast_node_to_location(
                context.ast_tree,
                node,
            ) or self.find_location_by_substring(context.code, f"def {node.name}")
            violations.append(
                Violation(
                    principle=principle,
                    severity=severity,
                    message=message,
                    location=loc,
                    suggestion="Rename to snake_case to match Python conventions.",
                ),
            )

        if isinstance(node, ast.Assign):
            for target in self._iter_assignment_targets(node.targets):
                if isinstance(target, ast.Name):
                    name = target.id
                    if name.isupper():
                        continue
                    if not self._is_snake_case(name):
                        loc = self.ast_node_to_location(
                            context.ast_tree,
                            target,
                        ) or self.find_location_by_substring(
                            context.code,
                            f"{name} =",
                        )
                        violations.append(
                            Violation(
                                principle=principle,
                                severity=severity,
                                message=message,
                                location=loc,
                                suggestion="Use snake_case for variable names.",
                            ),
                        )

    return violations

ShortVariableNamesDetector

ShortVariableNamesDetector()

Bases: ViolationDetector[ShortVariableNamesConfig], LocationHelperMixin

Detect variables and loop targets with names shorter than the configured minimum.

Single-letter variables like x, d, or n obscure intent and make grep-based navigation unreliable. Descriptive names (index, data, count) are self-documenting and reduce the need for inline comments.

Implements the "Readability counts" zen principle: code is read far more often than it is written, so names should communicate purpose.

Detection walks the AST for Assign, AnnAssign, AugAssign, For, and AsyncFor nodes. ALL_CAPS constants and a configurable allow-list of conventional loop names (i, j, k, _) are excluded. Falls back to regex heuristics on parse failure.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "short_variable_names" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Walk the AST and flag identifiers shorter than min_identifier_length.

Assignment targets (including tuple/list unpacking), annotated assignments, augmented assignments, and for/async for loop variables are all inspected. ALL_CAPS constants and names in allowed_loop_names are skipped.

PARAMETER DESCRIPTION
context

Analysis context with source text and parsed tree.

TYPE: AnalysisContext

config

Short-name detector thresholds (min_identifier_length, allowed_loop_names).

TYPE: ShortVariableNamesConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per overly short identifier.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(  # noqa: C901, PLR0912
    self,
    context: AnalysisContext,
    config: ShortVariableNamesConfig,
) -> list[Violation]:
    """Walk the AST and flag identifiers shorter than ``min_identifier_length``.

    Assignment targets (including tuple/list unpacking), annotated
    assignments, augmented assignments, and ``for``/``async for`` loop
    variables are all inspected.  ``ALL_CAPS`` constants and names in
    ``allowed_loop_names`` are skipped.

    Args:
        context (AnalysisContext): Analysis context with source text and parsed tree.
        config (ShortVariableNamesConfig): Short-name detector thresholds (``min_identifier_length``,
            ``allowed_loop_names``).

    Returns:
        list[Violation]: One violation per overly short identifier.
    """
    violations: list[Violation] = []
    min_len = config.min_identifier_length
    allowed_loop_names = set(config.allowed_loop_names)
    try:
        tree = (
            context.ast_tree.tree
            if isinstance(context.ast_tree, ParserResult)
            else context.ast_tree
        )
        if not isinstance(tree, ast.AST):
            tree = ast.parse(context.code)
    except (AttributeError, SyntaxError):
        return self._heuristic_detect(context, config)

    for node in ast.walk(tree):
        if isinstance(node, (ast.Assign, ast.AnnAssign, ast.AugAssign)):
            targets = []
            if isinstance(node, ast.Assign):
                targets = list(self._iter_assignment_targets(node.targets))
            else:
                targets = [getattr(node, "target", None)]
            for target in targets:
                if isinstance(target, ast.Name):
                    name = target.id
                    if name.isupper():
                        continue
                    if len(name) < min_len:
                        loc = self.ast_node_to_location(
                            context.ast_tree,
                            target,
                        ) or self.find_location_by_substring(
                            context.code,
                            f"{name} =",
                        )
                        violations.append(
                            self.build_violation(
                                config,
                                contains=name,
                                index=0,
                                location=loc,
                                suggestion=(
                                    "Use descriptive variable names for readability."
                                ),
                            ),
                        )
        elif isinstance(node, (ast.For, ast.AsyncFor)):
            target = node.target
            if isinstance(target, ast.Name):
                name = target.id
                if name.isupper() or name in allowed_loop_names:
                    continue
                if len(name) < min_len:
                    loc = self.ast_node_to_location(context.ast_tree, target)
                    violations.append(
                        self.build_violation(
                            config,
                            contains=name,
                            index=0,
                            location=loc,
                            suggestion=(
                                "Use descriptive loop variables instead of short names."
                            ),
                        ),
                    )
    return violations

CyclomaticComplexityDetector

CyclomaticComplexityDetector()

Bases: ViolationDetector[CyclomaticComplexityConfig], LocationHelperMixin

Detect functions whose cyclomatic complexity exceeds the configured threshold.

Cyclomatic complexity counts the number of independent execution paths through a function. High values correlate strongly with bug density and make unit testing exponentially harder because each path requires at least one test case.

Implements the "Simple is better than complex" zen principle: functions with low branching are easier to read, test, and maintain.

Detection reads the pre-computed context.cyclomatic_summary (populated by radon via MetricsCollector). Both the module-wide average and individual function blocks are checked. Per-block severity is scaled by how far the complexity exceeds the threshold.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "cyclomatic_complexity" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Check module-wide average and per-function cyclomatic complexity.

When the module average exceeds max_cyclomatic_complexity, a violation is emitted at the first def location. Individual function blocks that exceed the threshold also produce violations with severity scaled proportionally to the overshoot.

PARAMETER DESCRIPTION
context

Analysis context with a pre-computed cyclomatic_summary.

TYPE: AnalysisContext

config

Cyclomatic-complexity detector thresholds.

TYPE: CyclomaticComplexityConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per over-complex function, plus optionally one for the module-wide average.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CyclomaticComplexityConfig,
) -> list[Violation]:
    """Check module-wide average and per-function cyclomatic complexity.

    When the module average exceeds ``max_cyclomatic_complexity``, a
    violation is emitted at the first ``def`` location.  Individual
    function blocks that exceed the threshold also produce violations
    with severity scaled proportionally to the overshoot.

    Args:
        context (AnalysisContext): Analysis context with a pre-computed
            ``cyclomatic_summary``.
        config (CyclomaticComplexityConfig): Cyclomatic-complexity detector thresholds.

    Returns:
        list[Violation]: One violation per over-complex function, plus
            optionally one for the module-wide average.
    """
    violations: list[Violation] = []

    if context.cyclomatic_summary is None:
        return violations

    avg = context.cyclomatic_summary.average
    max_allowed = config.max_cyclomatic_complexity
    principle = _principle_text(config)
    base_severity = _severity_level(config)

    if avg > max_allowed:
        location = self._find_first_function_location(context)
        violations.append(
            Violation(
                principle=principle,
                severity=base_severity,
                message=_violation_message(config, contains="cyclomatic", index=0),
                location=location,
                suggestion="Reduce branching and split complex functions into smaller units.",
            ),
        )

    for block in context.cyclomatic_summary.blocks or []:
        if block.complexity > max_allowed:
            loc = Location(line=block.lineno, column=1)
            delta = max(block.complexity - max_allowed, 0)
            severity = min(9, base_severity + delta)
            violations.append(
                Violation(
                    principle=principle,
                    severity=severity,
                    message=_violation_message(
                        config,
                        contains="cyclomatic",
                        index=0,
                    ),
                    location=loc,
                    suggestion="Consider refactoring this function to reduce branching.",
                ),
            )

    return violations

NestingDepthDetector

NestingDepthDetector()

Bases: ViolationDetector[NestingDepthConfig], LocationHelperMixin

Detect code blocks with excessive indentation depth and nested loops.

Deeply nested code forces readers to maintain a large mental stack of conditions and scopes. Beyond three levels, bugs hide in corner cases that are nearly impossible to reason about during review.

Implements the "Flat is better than nested" zen principle: early returns, guard clauses, and helper functions keep nesting shallow.

Two checks are performed:

  1. Indentation-based nesting depth via detect_deep_nesting.
  2. AST-based loop nesting depth — nested for/while loops beyond depth 1 are flagged separately.
Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "nesting_depth" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Check indentation depth and loop nesting against thresholds.

First delegates to detect_deep_nesting for an indentation-based measurement. Then separately computes the maximum loop nesting depth via AST traversal and flags anything beyond depth 1.

PARAMETER DESCRIPTION
context

Analysis context with source text and parsed tree.

TYPE: AnalysisContext

config

Nesting-depth detector thresholds (max_nesting_depth).

TYPE: NestingDepthConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Up to two violations — one for general nesting, one for loop nesting.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: NestingDepthConfig,
) -> list[Violation]:
    """Check indentation depth and loop nesting against thresholds.

    First delegates to ``detect_deep_nesting`` for an indentation-based
    measurement.  Then separately computes the maximum loop nesting depth
    via AST traversal and flags anything beyond depth 1.

    Args:
        context (AnalysisContext): Analysis context with source text and parsed tree.
        config (NestingDepthConfig): Nesting-depth detector thresholds (``max_nesting_depth``).

    Returns:
        list[Violation]: Up to two violations — one for general nesting,
            one for loop nesting.
    """
    from mcp_zen_of_languages.rules.detections import detect_deep_nesting

    violations: list[Violation] = []
    max_allowed = config.max_nesting_depth
    principle = _principle_text(config)
    severity = _severity_level(config)

    is_deep, _depth = detect_deep_nesting(context.code, max_allowed)
    if is_deep:
        location = self._find_nested_location(context)
        violations.append(
            Violation(
                principle=principle,
                severity=severity,
                message=_violation_message(
                    config,
                    contains="Nesting depth",
                    index=0,
                ),
                location=location,
                suggestion=(
                    "Refactor deeply nested blocks into smaller functions or use early returns."
                ),
            ),
        )
    loop_depth = self._max_loop_depth(context)
    if loop_depth > 1:
        location = self.find_location_by_substring(
            context.code,
            "for ",
        ) or self.find_location_by_substring(context.code, "while ")
        violations.append(
            Violation(
                principle=principle,
                severity=severity,
                message=_violation_message(
                    config,
                    contains="nested loops",
                    index=0,
                ),
                location=location,
                suggestion="Flatten nested loops or extract inner logic.",
            ),
        )

    return violations

LongFunctionDetector

LongFunctionDetector()

Bases: ViolationDetector[LongFunctionConfig], LocationHelperMixin

Detect functions whose line count exceeds the configured maximum.

Long functions tend to do too much — mixing input validation, business logic, side effects, and formatting in a single scope. Shorter functions with descriptive names serve as self-documenting building blocks that are individually testable.

Implements the "Simple is better than complex" zen principle: small, focused functions are the foundation of maintainable code.

Detection delegates to detect_long_functions which measures each def block by line span.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "long_functions" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Delegate to detect_long_functions and emit violations for oversized defs.

Each function exceeding max_function_length lines produces one violation pinpointed to its def statement.

PARAMETER DESCRIPTION
context

Analysis context with source text and parsed tree.

TYPE: AnalysisContext

config

Long-function detector thresholds (max_function_length).

TYPE: LongFunctionConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per oversized function.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: LongFunctionConfig,
) -> list[Violation]:
    """Delegate to ``detect_long_functions`` and emit violations for oversized defs.

    Each function exceeding ``max_function_length`` lines produces one
    violation pinpointed to its ``def`` statement.

    Args:
        context (AnalysisContext): Analysis context with source text and parsed tree.
        config (LongFunctionConfig): Long-function detector thresholds (``max_function_length``).

    Returns:
        list[Violation]: One violation per oversized function.
    """
    from mcp_zen_of_languages.rules.detections import detect_long_functions

    violations: list[Violation] = []
    max_lines = config.max_function_length
    principle = _principle_text(config)
    severity = _severity_level(config)

    long_functions = detect_long_functions(code=context.code, max_lines=max_lines)

    for name, _length in long_functions:
        location = self._find_function_location(context, name)
        violations.append(
            Violation(
                principle=principle,
                severity=severity,
                message=_violation_message(
                    config,
                    contains="Functions longer",
                    index=0,
                ),
                location=location,
                suggestion="Split large functions into smaller, focused helpers.",
            ),
        )

    return violations

GodClassDetector

GodClassDetector()

Bases: ViolationDetector[GodClassConfig]

Detect God classes — classes with too many methods or lines of code.

A God class absorbs responsibilities that should be distributed across several smaller collaborating classes. They become magnets for change, difficult to test in isolation, and resistant to parallel development.

Implements the "Simple is better than complex" zen principle: each class should have a single, well-defined responsibility.

Detection delegates to detect_god_classes which counts methods and measures line span per class, comparing against max_methods and max_class_length.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "god_classes" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Delegate to detect_god_classes and flag classes that breach thresholds.

PARAMETER DESCRIPTION
context

Analysis context with source text.

TYPE: AnalysisContext

config

God-class detector thresholds (max_methods, max_class_length).

TYPE: GodClassConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per God class found.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: GodClassConfig,
) -> list[Violation]:
    """Delegate to ``detect_god_classes`` and flag classes that breach thresholds.

    Args:
        context (AnalysisContext): Analysis context with source text.
        config (GodClassConfig): God-class detector thresholds (``max_methods``,
            ``max_class_length``).

    Returns:
        list[Violation]: One violation per God class found.
    """
    from mcp_zen_of_languages.rules.detections import detect_god_classes

    violations: list[Violation] = []
    max_methods = config.max_methods
    max_lines = config.max_class_length
    principle = _principle_text(config)
    severity = _severity_level(config)

    god_classes = detect_god_classes(
        context.code,
        max_methods=max_methods,
        max_lines=max_lines,
    )

    violations.extend(
        Violation(
            principle=principle,
            severity=severity,
            message=_violation_message(config, contains="Classes longer", index=1),
            suggestion="Break the large class into smaller cohesive classes.",
        )
        for _ in god_classes
    )
    return violations

MagicMethodDetector

MagicMethodDetector()

Bases: ViolationDetector[MagicMethodConfig], LocationHelperMixin

Detect classes that overload too many dunder (magic) methods.

While dunder methods are powerful, overusing them creates an opaque API where the behaviour of operators like +, [], and == becomes hard to predict. A class implementing more than a handful of magic methods is often trying to act like a built-in type and should instead expose explicit method names.

Implements the "Explicit is better than implicit" zen principle: prefer named methods over operator overloading for non-obvious semantics.

Detection delegates to detect_magic_methods_overuse which collects all __dunder__ method definitions per class, then flags classes exceeding max_magic_methods.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "magic_methods" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Count dunder method definitions and flag when exceeding the threshold.

The violation is anchored at the first def __ occurrence in the source to guide the developer to the most relevant class.

PARAMETER DESCRIPTION
context

Analysis context with source text.

TYPE: AnalysisContext

config

Magic-method detector thresholds (max_magic_methods).

TYPE: MagicMethodConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: At most one violation when the count exceeds the configured maximum.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: MagicMethodConfig,
) -> list[Violation]:
    """Count dunder method definitions and flag when exceeding the threshold.

    The violation is anchored at the first ``def __`` occurrence in the
    source to guide the developer to the most relevant class.

    Args:
        context (AnalysisContext): Analysis context with source text.
        config (MagicMethodConfig): Magic-method detector thresholds (``max_magic_methods``).

    Returns:
        list[Violation]: At most one violation when the count exceeds the
            configured maximum.
    """
    from mcp_zen_of_languages.rules.detections import detect_magic_methods_overuse

    violations: list[Violation] = []

    magic_methods = detect_magic_methods_overuse(context.code)
    max_allowed = config.max_magic_methods
    principle = _principle_text(config)
    severity = _severity_level(config)

    if len(magic_methods) > max_allowed:
        location = self.find_location_by_substring(context.code, "def __")
        violations.append(
            Violation(
                principle=principle,
                severity=severity,
                message=_violation_message(config, contains="magic", index=2),
                location=location,
                suggestion="Avoid excessive operator overloading; prefer explicit APIs.",
            ),
        )

    return violations

CircularDependencyDetector

CircularDependencyDetector()

Bases: ViolationDetector[CircularDependencyConfig]

Detect circular import dependencies across modules.

Circular imports are a common source of ImportError at runtime and indicate tangled module responsibilities. They also prevent clean layering and make it impossible to understand a module in isolation.

Implements the "Flat is better than nested" zen principle applied to the dependency graph: modules should form a directed acyclic graph.

Detection uses the pre-built context.dependency_analysis graph edges and delegates cycle-finding to detect_dependency_cycles, which performs a topological sort and reports back-edges.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "circular_dependencies" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Extract dependency graph edges and flag any import cycles.

Skips detection entirely when no dependency_analysis is available (single-file mode without repository context).

PARAMETER DESCRIPTION
context

Analysis context with a pre-built dependency graph.

TYPE: AnalysisContext

config

Circular-dependency detector thresholds and rule metadata.

TYPE: CircularDependencyConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per import cycle detected.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: CircularDependencyConfig,
) -> list[Violation]:
    """Extract dependency graph edges and flag any import cycles.

    Skips detection entirely when no ``dependency_analysis`` is available
    (single-file mode without repository context).

    Args:
        context (AnalysisContext): Analysis context with a pre-built dependency graph.
        config (CircularDependencyConfig): Circular-dependency detector thresholds and rule metadata.

    Returns:
        list[Violation]: One violation per import cycle detected.
    """
    from mcp_zen_of_languages.rules.detections import detect_dependency_cycles

    violations: list[Violation] = []

    if context.dependency_analysis is None:
        return violations

    edges = getattr(context.dependency_analysis, "edges", None)
    if not edges:
        return violations

    cycles = detect_dependency_cycles(edges)
    principle = _principle_text(config)
    severity = _severity_level(config)

    violations.extend(
        Violation(
            principle=principle,
            severity=severity,
            message=_violation_message(config, contains="dependencies", index=0),
            suggestion="Refactor to break cycles or introduce interfaces/abstractions.",
        )
        for _ in cycles
    )
    return violations

DeepInheritanceDetector

DeepInheritanceDetector()

Bases: ViolationDetector[DeepInheritanceConfig]

Detect class hierarchies that exceed a safe inheritance depth.

Deep inheritance chains (more than two or three levels) create fragile base-class coupling, make method resolution order hard to predict, and encourage overriding rather than composing. Composition via delegation or mixins keeps each class understandable in isolation.

Implements the "Flat is better than nested" zen principle applied to type hierarchies: shallow, wide hierarchies beat deep, narrow ones.

Detection requires multi-file context (context.other_files). It delegates to detect_deep_inheritance which traces class parents across all provided source files.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "deep_inheritance" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Trace class parent chains across files and flag excessive depth.

Requires context.other_files for cross-file class resolution; returns an empty list in single-file mode.

PARAMETER DESCRIPTION
context

Analysis context with source text and sibling file map.

TYPE: AnalysisContext

config

Deep-inheritance detector thresholds and rule metadata.

TYPE: DeepInheritanceConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per inheritance chain exceeding the configured depth.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: DeepInheritanceConfig,
) -> list[Violation]:
    """Trace class parent chains across files and flag excessive depth.

    Requires ``context.other_files`` for cross-file class resolution;
    returns an empty list in single-file mode.

    Args:
        context (AnalysisContext): Analysis context with source text and sibling file map.
        config (DeepInheritanceConfig): Deep-inheritance detector thresholds and rule metadata.

    Returns:
        list[Violation]: One violation per inheritance chain exceeding the
            configured depth.
    """
    from mcp_zen_of_languages.rules.detections import detect_deep_inheritance

    violations: list[Violation] = []

    if not context.other_files:
        return violations

    all_files = {
        **(context.other_files or {}),
        (context.path or "<current>"): context.code,
    }
    inheritance_chains = detect_deep_inheritance(all_files)
    principle = _principle_text(config)
    severity = _severity_level(config)

    violations.extend(
        Violation(
            principle=principle,
            severity=severity,
            message=_violation_message(config, contains="inheritance", index=1),
            suggestion="Favor composition over deep inheritance.",
        )
        for _ in inheritance_chains
    )
    return violations

FeatureEnvyDetector

FeatureEnvyDetector()

Bases: ViolationDetector[FeatureEnvyConfig]

Detect methods that access another object's data more than their own.

Feature envy is a classic code smell where a method in class A repeatedly reaches into class B's attributes. This suggests the method belongs on B (or on a shared helper) rather than A, and its presence on A couples the two classes unnecessarily.

Implements the "There should be one obvious way to do it" zen principle: behaviour should live next to the data it operates on.

Detection delegates to detect_feature_envy and filters results by min_occurrences to avoid flagging incidental cross-object access.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "feature_envy" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Identify methods excessively accessing another object's attributes.

Results from detect_feature_envy are filtered by min_occurrences to suppress noise from incidental attribute reads.

PARAMETER DESCRIPTION
context

Analysis context with source text.

TYPE: AnalysisContext

config

Feature-envy detector thresholds (min_occurrences).

TYPE: FeatureEnvyConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per envious method exceeding the occurrence threshold.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: FeatureEnvyConfig,
) -> list[Violation]:
    """Identify methods excessively accessing another object's attributes.

    Results from ``detect_feature_envy`` are filtered by
    ``min_occurrences`` to suppress noise from incidental attribute
    reads.

    Args:
        context (AnalysisContext): Analysis context with source text.
        config (FeatureEnvyConfig): Feature-envy detector thresholds (``min_occurrences``).

    Returns:
        list[Violation]: One violation per envious method exceeding the
            occurrence threshold.
    """
    from mcp_zen_of_languages.rules.detections import detect_feature_envy

    violations: list[Violation] = []
    min_occurrences = config.min_occurrences
    principle = _principle_text(config)
    severity = _severity_level(config)

    feature_envies = detect_feature_envy(context.code)
    feature_envies = [
        e for e in feature_envies if getattr(e, "occurrences", 0) >= min_occurrences
    ]

    violations.extend(
        Violation(
            principle=principle,
            severity=severity,
            message=_violation_message(
                config,
                contains="Multiple implementations",
                index=3,
            ),
            suggestion="Consider moving the method to the target class or extracting a helper.",
        )
        for _ in feature_envies
    )
    return violations

DuplicateImplementationDetector

DuplicateImplementationDetector()

Bases: ViolationDetector[DuplicateImplementationConfig]

Detect identical or near-identical function implementations across files.

Copy-pasted logic creates a maintenance multiplier — every bug fix or feature change must be applied in multiple places, and divergence over time turns copies into subtle variants with different edge-case handling.

Implements the "There should be one obvious way to do it" zen principle: shared logic should live in a single canonical location.

Detection requires multi-file context (context.other_files). It delegates to detect_multiple_implementations which compares function bodies across the provided source map.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "duplicate_implementations" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Compare function bodies across files and flag duplicates.

Merges context.other_files with the current file, then delegates to detect_multiple_implementations. Skips detection in single-file mode.

PARAMETER DESCRIPTION
context

Analysis context with source text and sibling file map.

TYPE: AnalysisContext

config

Duplicate-implementation detector thresholds and rule metadata.

TYPE: DuplicateImplementationConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per group of duplicated functions, with the files field listing affected paths.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: DuplicateImplementationConfig,
) -> list[Violation]:
    """Compare function bodies across files and flag duplicates.

    Merges ``context.other_files`` with the current file, then delegates
    to ``detect_multiple_implementations``.  Skips detection in
    single-file mode.

    Args:
        context (AnalysisContext): Analysis context with source text and sibling file map.
        config (DuplicateImplementationConfig): Duplicate-implementation detector thresholds and rule
            metadata.

    Returns:
        list[Violation]: One violation per group of duplicated functions,
            with the ``files`` field listing affected paths.
    """
    from mcp_zen_of_languages.rules.detections import (
        detect_multiple_implementations,
    )

    violations: list[Violation] = []

    if not context.other_files:
        return violations

    all_files = {
        **(context.other_files or {}),
        (context.path or "<current>"): context.code,
    }
    duplicates = detect_multiple_implementations(all_files)
    principle = _principle_text(config)
    severity = _severity_level(config)

    violations.extend(
        Violation(
            principle=principle,
            severity=severity,
            message=_violation_message(
                config,
                contains="Multiple implementations",
                index=3,
            ),
            files=duplicate.files,
            suggestion="Consolidate duplicated implementations into a single utility or module.",
        )
        for duplicate in duplicates
    )
    return violations

SparseCodeDetector

SparseCodeDetector()

Bases: ViolationDetector[SparseCodeConfig], LocationHelperMixin

Detect lines packing multiple statements separated by semicolons.

Cramming several statements onto one line (x = 1; y = 2; z = 3) makes code harder to read, harder to step through in a debugger, and breaks the one-statement-per-line convention that most Python style guides assume.

Implements the "Sparse is better than dense" zen principle: each line should do one thing clearly.

Detection delegates to detect_sparse_code which counts semicolon- separated statements per line and reports those exceeding max_statements_per_line.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "sparse_code" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Flag lines containing more than max_statements_per_line statements.

PARAMETER DESCRIPTION
context

Analysis context with source text.

TYPE: AnalysisContext

config

Sparse-code detector thresholds (max_statements_per_line).

TYPE: SparseCodeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per overly dense line.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: SparseCodeConfig,
) -> list[Violation]:
    """Flag lines containing more than ``max_statements_per_line`` statements.

    Args:
        context (AnalysisContext): Analysis context with source text.
        config (SparseCodeConfig): Sparse-code detector thresholds (``max_statements_per_line``).

    Returns:
        list[Violation]: One violation per overly dense line.
    """
    from mcp_zen_of_languages.rules.detections import detect_sparse_code

    violations: list[Violation] = []
    max_statements = config.max_statements_per_line
    principle = _principle_text(config)
    severity = _severity_level(config)

    for finding in detect_sparse_code(context.code, max_statements):
        loc = Location(line=finding.line, column=1)
        violations.append(
            Violation(
                principle=principle,
                severity=severity,
                message=_violation_message(
                    config,
                    contains="Multiple statements",
                    index=0,
                ),
                location=loc,
                suggestion="Split statements across lines to improve readability.",
            ),
        )

    return violations

ConsistencyDetector

ConsistencyDetector()

Bases: ViolationDetector[ConsistencyConfig], LocationHelperMixin

Detect mixed naming conventions within a single module.

A module that uses both camelCase and snake_case (or other styles) signals either multiple authors with different habits or unfinished refactoring. Inconsistency forces readers to context-switch between conventions and erodes trust in the codebase.

Implements the "There should be one obvious way to do it" zen principle: pick one naming style and apply it everywhere.

Detection delegates to detect_inconsistent_naming_styles and flags when the number of distinct styles exceeds max_naming_styles.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "consistency" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Count distinct naming styles and flag when too many coexist.

The violation is anchored at the first def statement since naming inconsistency is inherently module-wide rather than localised.

PARAMETER DESCRIPTION
context

Analysis context with source text.

TYPE: AnalysisContext

config

Consistency detector thresholds (max_naming_styles).

TYPE: ConsistencyConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: At most one violation when the style count exceeds the threshold.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: ConsistencyConfig,
) -> list[Violation]:
    """Count distinct naming styles and flag when too many coexist.

    The violation is anchored at the first ``def`` statement since naming
    inconsistency is inherently module-wide rather than localised.

    Args:
        context (AnalysisContext): Analysis context with source text.
        config (ConsistencyConfig): Consistency detector thresholds (``max_naming_styles``).

    Returns:
        list[Violation]: At most one violation when the style count
            exceeds the threshold.
    """
    from mcp_zen_of_languages.rules.detections import (
        detect_inconsistent_naming_styles,
    )

    violations: list[Violation] = []
    max_styles = config.max_naming_styles
    principle = _principle_text(config)
    severity = _severity_level(config)

    findings = detect_inconsistent_naming_styles(context.code)
    if findings and len(findings[0].naming_styles) > max_styles:
        loc = self.find_location_by_substring(context.code, "def ")
        violations.append(
            Violation(
                principle=principle,
                severity=severity,
                message=_violation_message(
                    config,
                    contains="Different naming",
                    index=1,
                ),
                location=loc,
                suggestion="Use a single naming style consistently (e.g., snake_case).",
            ),
        )

    return violations

ExplicitnessDetector

ExplicitnessDetector()

Bases: ViolationDetector[ExplicitnessConfig], LocationHelperMixin

Detect function parameters missing type annotations.

Type hints are the primary documentation channel for Python function contracts. Without them, callers must read the implementation to discover expected types, and static analysis tools like mypy and pyright cannot verify call-site correctness.

Implements the "Explicit is better than implicit" zen principle: annotated signatures make interfaces self-describing and machine- checkable.

Detection is gated on config.require_type_hints and delegates to detect_missing_type_hints which parses function signatures for un-annotated parameters.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "explicitness" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Scan function signatures for un-annotated parameters.

No-ops when config.require_type_hints is False, allowing projects to opt out of this check.

PARAMETER DESCRIPTION
context

Analysis context with source text.

TYPE: AnalysisContext

config

Explicitness detector thresholds (require_type_hints).

TYPE: ExplicitnessConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per function with missing type annotations.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: ExplicitnessConfig,
) -> list[Violation]:
    """Scan function signatures for un-annotated parameters.

    No-ops when ``config.require_type_hints`` is ``False``, allowing
    projects to opt out of this check.

    Args:
        context (AnalysisContext): Analysis context with source text.
        config (ExplicitnessConfig): Explicitness detector thresholds (``require_type_hints``).

    Returns:
        list[Violation]: One violation per function with missing type
            annotations.
    """
    if not config.require_type_hints:
        return []

    from mcp_zen_of_languages.rules.detections import detect_missing_type_hints

    violations: list[Violation] = []
    principle = _principle_text(config)
    severity = _severity_level(config)

    for finding in detect_missing_type_hints(context.code):
        loc = self.find_location_by_substring(
            context.code,
            f"def {finding.function}",
        )
        violations.append(
            Violation(
                principle=principle,
                severity=severity,
                message=_violation_message(
                    config,
                    contains="Missing input",
                    index=2,
                ),
                location=loc,
                suggestion="Add explicit type hints to function parameters.",
            ),
        )

    return violations

NamespaceUsageDetector

NamespaceUsageDetector()

Bases: ViolationDetector[NamespaceConfig], LocationHelperMixin

Detect modules with too many top-level symbols or __all__ exports.

A module that defines dozens of public names is likely doing too much and should be split into sub-modules. Overly large __all__ lists signal the same problem from the export side. Keeping modules focused makes imports predictable and navigation fast.

Implements the "Namespaces are one honking great idea" zen principle: each module should own a narrow, well-defined slice of the namespace.

Detection delegates to detect_namespace_usage which counts top-level symbols and __all__ entries, comparing against max_top_level_symbols and max_exports.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return "namespace_usage" for detector registry lookup.

RETURNS DESCRIPTION
str

Registry key used to wire this detector to its rule config.

TYPE: str

Functions
detect
detect(context, config)

Count top-level symbols and __all__ entries against thresholds.

Two independent checks are performed: one for total top-level symbol count and one for __all__ export count. Either or both may fire.

PARAMETER DESCRIPTION
context

Analysis context with source text.

TYPE: AnalysisContext

config

Namespace detector thresholds (max_top_level_symbols, max_exports).

TYPE: NamespaceConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Up to two violations — one for symbols, one for exports.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: NamespaceConfig,
) -> list[Violation]:
    """Count top-level symbols and ``__all__`` entries against thresholds.

    Two independent checks are performed: one for total top-level symbol
    count and one for ``__all__`` export count.  Either or both may fire.

    Args:
        context (AnalysisContext): Analysis context with source text.
        config (NamespaceConfig): Namespace detector thresholds (``max_top_level_symbols``,
            ``max_exports``).

    Returns:
        list[Violation]: Up to two violations — one for symbols, one for
            exports.
    """
    from mcp_zen_of_languages.rules.detections import detect_namespace_usage

    violations: list[Violation] = []
    principle = _principle_text(config)
    severity = _severity_level(config)

    finding = detect_namespace_usage(context.code)
    if finding.top_level_symbols > config.max_top_level_symbols:
        violations.append(
            Violation(
                principle=principle,
                severity=severity,
                message=_violation_message(config, contains="Polluting", index=0),
                suggestion="Refactor to reduce module-level symbols or split the module.",
            ),
        )
    if (
        finding.export_count is not None
        and finding.export_count > config.max_exports
    ):
        violations.append(
            Violation(
                principle=principle,
                severity=severity,
                message=_violation_message(config, contains="__all__", index=1),
                suggestion="Reduce __all__ exports or split the module into submodules.",
            ),
        )

    return violations

PythonPracticalityDetector

PythonPracticalityDetector()

Bases: ViolationDetector[PythonPracticalityConfig]

Flags over-engineered abstractions like ABCs with likely few implementations.

Python's "practicality beats purity" principle discourages premature abstraction.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect over-engineered abstractions.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: PythonPracticalityConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PythonPracticalityConfig,
) -> list[Violation]:
    """Detect over-engineered abstractions.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (PythonPracticalityConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(r"\bclass\s+\w+\s*\(\s*(ABC|Protocol)\s*\)", context.code):
        return [
            self.build_violation(
                config,
                contains="ABC",
                suggestion="Prefer simple, practical solutions over excessive abstraction.",
            ),
        ]
    return []

PythonExplicitSilenceDetector

PythonExplicitSilenceDetector()

Bases: ViolationDetector[PythonExplicitSilenceConfig]

Detects bare except clauses and silently caught exceptions.

Errors should never pass silently unless explicitly silenced.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect bare except and silent catch patterns.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: PythonExplicitSilenceConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PythonExplicitSilenceConfig,
) -> list[Violation]:
    """Detect bare except and silent catch patterns.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (PythonExplicitSilenceConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    violations: list[Violation] = []
    if re.search(r"\bexcept\s*:", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="bare except",
                suggestion="Catch specific exceptions; never use bare except.",
            ),
        )
    if re.search(r"\bexcept\s+\w[\w.]*\s*:.*\n\s*pass\b", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="silent catch",
                suggestion="Log or re-raise caught exceptions; don't silently pass.",
            ),
        )
    return violations

PythonTodoStubDetector

PythonTodoStubDetector()

Bases: ViolationDetector[PythonTodoStubConfig]

Detects TODO, FIXME, HACK, and XXX comments left in source code.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect TODO/FIXME/HACK/XXX comment markers.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: PythonTodoStubConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PythonTodoStubConfig,
) -> list[Violation]:
    """Detect TODO/FIXME/HACK/XXX comment markers.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (PythonTodoStubConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(r"#\s*(TODO|FIXME|HACK|XXX)\b", context.code):
        return [
            self.build_violation(
                config,
                contains="TODO",
                suggestion="Address TODO/FIXME items; don't leave stubs unimplemented.",
            ),
        ]
    return []

PythonPrematureImplDetector

PythonPrematureImplDetector()

Bases: ViolationDetector[PythonPrematureImplConfig]

Detects raise NotImplementedError stubs without documentation.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect NotImplementedError raises.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: PythonPrematureImplConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PythonPrematureImplConfig,
) -> list[Violation]:
    """Detect NotImplementedError raises.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (PythonPrematureImplConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(r"raise\s+NotImplementedError", context.code):
        return [
            self.build_violation(
                config,
                contains="NotImplementedError",
                suggestion="Document why functionality is not yet implemented.",
            ),
        ]
    return []

PythonComplexUndocumentedDetector

PythonComplexUndocumentedDetector()

Bases: ViolationDetector[PythonComplexUndocumentedConfig]

Detects functions missing docstrings.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect functions without docstrings.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: PythonComplexUndocumentedConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PythonComplexUndocumentedConfig,
) -> list[Violation]:
    """Detect functions without docstrings.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (PythonComplexUndocumentedConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    violations: list[Violation] = []
    pattern = re.compile(
        r"def\s+(\w+)\s*\([^)]*\)\s*(?:->\s*[^:]+)?:\s*\n(?!\s*(\"\"\"|'''))",
    )
    for match in pattern.finditer(context.code):
        fn_name = match.group(1)
        violations.append(
            self.build_violation(
                config,
                contains=fn_name,
                suggestion=f"Add a docstring to {fn_name}() to explain the implementation.",
            ),
        )
    return violations

PythonSimpleDocumentedDetector

PythonSimpleDocumentedDetector()

Bases: ViolationDetector[PythonSimpleDocumentedConfig]

Detects public functions (not starting with _) missing docstrings.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect public functions without docstrings.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: PythonSimpleDocumentedConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PythonSimpleDocumentedConfig,
) -> list[Violation]:
    """Detect public functions without docstrings.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (PythonSimpleDocumentedConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    violations: list[Violation] = []
    pattern = re.compile(
        r"def\s+(?!_)(\w+)\s*\([^)]*\)\s*(?:->\s*[^:]+)?:\s*\n(?!\s*(\"\"\"|'''))",
    )
    for match in pattern.finditer(context.code):
        fn_name = match.group(1)
        violations.append(
            self.build_violation(
                config,
                contains=fn_name,
                suggestion=f"Consider adding a docstring to {fn_name}().",
            ),
        )
    return violations

PythonIdiomDetector

PythonIdiomDetector()

Bases: ViolationDetector[PythonIdiomConfig]

Detects non-idiomatic Python patterns like range(len(...)) and == True.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect non-idiomatic Python patterns.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: PythonIdiomConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/python/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: PythonIdiomConfig,
) -> list[Violation]:
    """Detect non-idiomatic Python patterns.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (PythonIdiomConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    violations: list[Violation] = []
    if re.search(r"range\s*\(\s*len\s*\(", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="range(len(",
                suggestion="Use enumerate() instead of range(len()).",
            ),
        )
    if re.search(r"==\s*True\b|==\s*False\b", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="== True",
                suggestion="Use direct boolean checks instead of == True/False.",
            ),
        )
    return violations

Ruby

mcp_zen_of_languages.languages.ruby.detectors

Zen-rule detectors for Ruby code quality, naming, and architecture checks.

Each detector implements the Strategy pattern as a ViolationDetector subclass, targeting a specific Ruby anti-pattern. Ruby's dynamic runtime and convention-driven culture make disciplined naming, restrained metaprogramming, and idiomatic block usage essential for maintainable code.

See Also

RubyAnalyzer: Template Method analyzer that orchestrates these detectors.

Classes

RubyNamingConventionDetector

RubyNamingConventionDetector()

Bases: ViolationDetector[RubyNamingConventionConfig], LocationHelperMixin

Flags Ruby methods defined with non-snake_case names.

Ruby's community universally expects snake_case for method and variable names. A method starting with an uppercase letter looks like a constant or class reference, breaking the readability contract that Rubyists rely on when scanning code without explicit type annotations.

Note

Only catches def UpperCase patterns; does not inspect local variables.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_naming_convention' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the naming-convention rule.

TYPE: str

Functions
detect
detect(context, config)

Scan method definitions for non-snake_case names.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Threshold configuration for naming conventions.

TYPE: RubyNamingConventionConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per method using non-snake_case naming.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyNamingConventionConfig,
) -> list[Violation]:
    """Scan method definitions for non-snake_case names.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyNamingConventionConfig): Threshold configuration for naming conventions.

    Returns:
        list[Violation]: One violation per method using non-snake_case naming.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="snake_case",
            location=Location(line=idx, column=1),
            suggestion="Use snake_case for method names.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"def\s+[A-Z]", line)
    ]
    return violations

RubyMethodChainDetector

RubyMethodChainDetector()

Bases: ViolationDetector[RubyMethodChainConfig], LocationHelperMixin

Detects excessively long method chains that reduce readability.

Ruby's fluent API style encourages chaining, but overly long chains become hard to debug and produce cryptic NoMethodError traces. Breaking chains into named intermediate variables clarifies intent and makes each transformation step independently testable.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_method_chain' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the method-chain-length rule.

TYPE: str

Functions
detect
detect(context, config)

Flag lines where the number of chained method calls exceeds the threshold.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Contains max_method_chain_length threshold.

TYPE: RubyMethodChainConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyMethodChainConfig,
) -> list[Violation]:
    """Flag lines where the number of chained method calls exceeds the threshold.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyMethodChainConfig): Contains ``max_method_chain_length`` threshold.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    max_chain = config.max_method_chain_length
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="chain",
            location=Location(line=idx, column=1),
            suggestion=f"Limit method chains to <= {max_chain} calls.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if line.count(".") > max_chain
    ]
    return violations

RubyDryDetector

RubyDryDetector()

Bases: ViolationDetector[RubyDryConfig], LocationHelperMixin

Identifies duplicated code lines that violate Don't Repeat Yourself (DRY).

Repeated non-trivial lines signal copy-paste programming, a common anti-pattern in Ruby projects that grow without refactoring. Extracting shared logic into methods, modules, or concerns keeps Ruby codebases concise and aligned with the principle that every piece of knowledge should have a single authoritative representation.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_dry' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the DRY rule.

TYPE: str

Functions
detect
detect(context, config)

Flag source files containing three or more identical non-blank lines.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

DRY threshold configuration.

TYPE: RubyDryConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyDryConfig,
) -> list[Violation]:
    """Flag source files containing three or more identical non-blank lines.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyDryConfig): DRY threshold configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    counts: dict[str, int] = {}
    for line in context.code.splitlines():
        stripped = line.strip()
        if not stripped or stripped.startswith("#"):
            continue
        counts[stripped] = counts.get(stripped, 0) + 1
        if counts[stripped] >= MIN_DUPLICATE_LINE_COUNT:
            return [
                self.build_violation(
                    config,
                    contains="duplication",
                    suggestion="Extract repeated code into methods or modules.",
                ),
            ]
    return []

RubyBlockPreferenceDetector

RubyBlockPreferenceDetector()

Bases: ViolationDetector[RubyBlockPreferenceConfig], LocationHelperMixin

Flags use of lambda/Proc.new where idiomatic blocks would suffice.

Ruby blocks (do...end / {...}) are the idiomatic way to pass closures for iteration and callbacks. Reaching for lambda or Proc.new when a simple block works adds unnecessary ceremony and confuses readers who expect the conventional block form in everyday enumerable pipelines.

Note

lambda is appropriate for stored callables; this detector targets cases where a block would be more natural.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_block_preference' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the block-preference rule.

TYPE: str

Functions
detect
detect(context, config)

Flag files that use lambda or Proc.new instead of blocks.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Block-preference threshold configuration.

TYPE: RubyBlockPreferenceConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyBlockPreferenceConfig,
) -> list[Violation]:
    """Flag files that use ``lambda`` or ``Proc.new`` instead of blocks.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyBlockPreferenceConfig): Block-preference threshold configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "lambda" in context.code or "Proc.new" in context.code:
        return [
            self.build_violation(
                config,
                contains="lambda",
                suggestion="Prefer blocks for simple iterations and callbacks.",
            ),
        ]
    return []

RubyMonkeyPatchDetector

RubyMonkeyPatchDetector()

Bases: ViolationDetector[RubyMonkeyPatchConfig], LocationHelperMixin

Detects reopening of core Ruby classes (monkey patching).

Monkey patching String, Array, Hash, or numeric classes silently mutates shared global state, creating action-at-a-distance bugs that are notoriously difficult to diagnose. In Ruby's open-class system any gem or initializer can redefine core behaviour, leading to conflicts between libraries and unpredictable runtime failures.

Note

Refinements (Module#refine) are the safe alternative for scoped extensions to core classes.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_monkey_patch' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the monkey-patching rule.

TYPE: str

Functions
detect
detect(context, config)

Flag class reopenings of built-in Ruby types like String or Array.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Monkey-patch detection configuration.

TYPE: RubyMonkeyPatchConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyMonkeyPatchConfig,
) -> list[Violation]:
    """Flag class reopenings of built-in Ruby types like String or Array.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyMonkeyPatchConfig): Monkey-patch detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    pattern = re.compile(r"^\s*class\s+(String|Array|Hash|Integer|Float)\b")
    violations.extend(
        self.build_violation(
            config,
            contains="monkey patch",
            location=Location(line=idx, column=1),
            suggestion="Avoid monkey-patching Ruby core classes.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if pattern.search(line)
    )
    return violations

RubyMethodNamingDetector

RubyMethodNamingDetector()

Bases: ViolationDetector[RubyMethodNamingConfig], LocationHelperMixin

Flags boolean-style methods that lack the conventional trailing ?.

Ruby convention dictates that predicate methods end with ? (e.g., empty?, valid?). A method named is_active or has_items without the ? suffix breaks the expectation of every Ruby developer, making boolean intent invisible at call sites and undermining Ruby's expressive readability.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_method_naming' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the boolean-method naming rule.

TYPE: str

Functions
detect
detect(context, config)

Flag methods starting with is/has that are missing a ? suffix.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Method-naming threshold configuration.

TYPE: RubyMethodNamingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyMethodNamingConfig,
) -> list[Violation]:
    """Flag methods starting with ``is``/``has`` that are missing a ``?`` suffix.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyMethodNamingConfig): Method-naming threshold configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.search(r"\bdef\s+([a-zA-Z_]\w*)", line)
        if not match:
            continue
        name = match[1]
        if name.startswith(("is", "has")) and not name.endswith("?"):
            violations.append(
                self.build_violation(
                    config,
                    contains=name,
                    location=Location(line=idx, column=match.start(1) + 1),
                    suggestion="Boolean methods should end with ?.",
                ),
            )
    return violations

RubySymbolKeysDetector

RubySymbolKeysDetector()

Bases: ViolationDetector[RubySymbolKeysConfig], LocationHelperMixin

Flags hash literals using string keys instead of idiomatic symbol keys.

Symbols are immutable, interned identifiers that are cheaper to compare and allocate than strings. Using 'key' => value instead of key: value wastes memory in long-lived hashes and signals unfamiliarity with Ruby's modern hash syntax introduced in Ruby 1.9.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_symbol_keys' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the symbol-keys rule.

TYPE: str

Functions
detect
detect(context, config)

Flag hash literals that use quoted string keys with => syntax.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Symbol-keys detection configuration.

TYPE: RubySymbolKeysConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubySymbolKeysConfig,
) -> list[Violation]:
    """Flag hash literals that use quoted string keys with ``=>`` syntax.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubySymbolKeysConfig): Symbol-keys detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="string keys",
            location=Location(line=idx, column=1),
            suggestion="Use symbols for hash keys.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"['\"][^'\"]+['\"]\s*=>", line)
    ]
    return violations

RubyGuardClauseDetector

RubyGuardClauseDetector()

Bases: ViolationDetector[RubyGuardClauseConfig], LocationHelperMixin

Detects methods that could benefit from guard clauses to reduce nesting.

Deeply nested if blocks obscure the happy path. Ruby's return if / return unless guard clauses let methods exit early, keeping the main logic at the top indentation level and making methods dramatically easier to read and maintain.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_guard_clause' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the guard-clause rule.

TYPE: str

Functions
detect
detect(context, config)

Flag code with if blocks that lack return if/unless guard clauses.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Guard-clause detection configuration.

TYPE: RubyGuardClauseConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyGuardClauseConfig,
) -> list[Violation]:
    """Flag code with ``if`` blocks that lack ``return if/unless`` guard clauses.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyGuardClauseConfig): Guard-clause detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    code = context.code
    if "if " in code and not re.search(r"\breturn\s+(if|unless)\b", code):
        return [
            self.build_violation(
                config,
                contains="guard clause",
                suggestion="Use guard clauses (return if/unless) to reduce nesting.",
            ),
        ]
    return []

RubyMetaprogrammingDetector

RubyMetaprogrammingDetector()

Bases: ViolationDetector[RubyMetaprogrammingConfig], LocationHelperMixin

Flags dangerous metaprogramming constructs like method_missing and eval.

Ruby's metaprogramming power—define_method, method_missing, class_eval, instance_eval, and dynamic send—can make code impossible to trace statically, defeats IDE navigation, and hides method signatures from documentation tools. Unrestricted use turns a codebase into a maze where any object may respond to any message at runtime, making debugging and security auditing extremely difficult.

Note

Metaprogramming is acceptable in DSL frameworks; this detector highlights it so teams can make conscious, documented decisions.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_metaprogramming' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the metaprogramming-restraint rule.

TYPE: str

Functions
detect
detect(context, config)

Flag code containing dynamic dispatch or runtime method generation.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Metaprogramming detection configuration.

TYPE: RubyMetaprogrammingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyMetaprogrammingConfig,
) -> list[Violation]:
    """Flag code containing dynamic dispatch or runtime method generation.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyMetaprogrammingConfig): Metaprogramming detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    return next(
        (
            [
                self.build_violation(
                    config,
                    contains=token,
                    suggestion="Avoid metaprogramming unless strictly necessary.",
                ),
            ]
            for token in (
                "define_method",
                "method_missing",
                "class_eval",
                "instance_eval",
                "send(",
                "public_send(",
            )
            if token in context.code
        ),
        [],
    )

RubyExpressiveSyntaxDetector

RubyExpressiveSyntaxDetector()

Bases: ViolationDetector[RubyExpressiveSyntaxConfig], LocationHelperMixin

Flags non-idiomatic control flow like C-style for loops and unless !.

Ruby provides each, map, select, and other Enumerable methods that are more expressive and less error-prone than for...in loops. Similarly, unless !condition is a double-negative that should be written as if condition. Using these non-idiomatic constructs signals unfamiliarity with Ruby's expressive design philosophy.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_expressive_syntax' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the expressive-syntax rule.

TYPE: str

Functions
detect
detect(context, config)

Flag for...in loops and unless ! double-negatives.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Expressive-syntax detection configuration.

TYPE: RubyExpressiveSyntaxConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyExpressiveSyntaxConfig,
) -> list[Violation]:
    """Flag ``for...in`` loops and ``unless !`` double-negatives.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyExpressiveSyntaxConfig): Expressive-syntax detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    return next(
        (
            [
                self.build_violation(
                    config,
                    contains="expressive syntax",
                    location=Location(line=idx, column=1),
                    suggestion="Prefer each/if over for/unless !.",
                ),
            ]
            for idx, line in enumerate(context.code.splitlines(), start=1)
            if re.search(r"^\s*for\s+\w+\s+in\s+", line) or "unless !" in line
        ),
        [],
    )

RubyPreferFailDetector

RubyPreferFailDetector()

Bases: ViolationDetector[RubyPreferFailConfig], LocationHelperMixin

Flags use of raise where fail is the preferred convention for programmer errors.

The Ruby community convention (popularized by RuboCop) reserves fail for signalling programmer errors in methods and raise for re-raising exceptions in rescue blocks. Consistent use of fail for initial error signalling makes it immediately obvious whether an exception is being raised for the first time or re-raised after partial handling.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'ruby_prefer_fail' for registry wiring.

RETURNS DESCRIPTION
str

Detector identifier for the prefer-fail rule.

TYPE: str

Functions
detect
detect(context, config)

Flag files that use raise without any corresponding fail calls.

PARAMETER DESCRIPTION
context

Analysis context with Ruby source text.

TYPE: AnalysisContext

config

Prefer-fail detection configuration.

TYPE: RubyPreferFailConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/ruby/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RubyPreferFailConfig,
) -> list[Violation]:
    """Flag files that use ``raise`` without any corresponding ``fail`` calls.

    Args:
        context (AnalysisContext): Analysis context with Ruby source text.
        config (RubyPreferFailConfig): Prefer-fail detection configuration.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "raise " in context.code and "fail " not in context.code:
        return [
            self.build_violation(
                config,
                contains="raise",
                suggestion="Use fail for programmer errors.",
            ),
        ]
    return []

Rust

mcp_zen_of_languages.languages.rust.detectors

Rule detectors for rust code quality and architecture checks.

Classes

RustUnwrapUsageDetector

RustUnwrapUsageDetector()

Bases: ViolationDetector[RustUnwrapUsageConfig]

Flags excessive unwrap() and expect() calls that bypass Rust's error model.

Rust's Result and Option types encode fallibility in the type system, but unwrap() and expect() short-circuit that safety by panicking on Err or None. In library code, panics are unrecoverable by callers. This detector uses a regex to count .unwrap( and .expect( occurrences and flags files that exceed the configured maximum.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustUnwrapUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustUnwrapUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustUnwrapUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    count = len(re.findall(r"\.unwrap\s*\(|\.expect\s*\(", context.code))
    if count > config.max_unwraps:
        violations.append(
            self.build_violation(
                config,
                contains="unwrap",
                index=0,
                suggestion="Use ? or match with proper error handling instead of unwrap/expect.",
            ),
        )
    return violations

RustUnsafeBlocksDetector

RustUnsafeBlocksDetector()

Bases: ViolationDetector[RustUnsafeBlocksConfig]

Ensures every unsafe block is preceded by a // SAFETY: comment.

Rust allows opting out of borrow-checker guarantees with unsafe, but the Rust community convention requires a // SAFETY: comment explaining why the invariants hold. This detector scans each line containing the unsafe keyword and checks the preceding two lines for the required safety justification, skipping commented-out code.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustUnsafeBlocksConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustUnsafeBlocksConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustUnsafeBlocksConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if not config.detect_unsafe_blocks:
        return []
    violations: list[Violation] = []
    lines = context.code.splitlines()
    for idx, line in enumerate(lines):
        if not re.search(r"\bunsafe\b", line):
            continue
        if line.strip().startswith("//"):
            continue
        has_comment = any(
            "// SAFETY:" in lines[back] for back in range(max(0, idx - 2), idx)
        )
        if not has_comment:
            violations.append(
                self.build_violation(
                    config,
                    contains="safety comments",
                    index=0,
                    suggestion=(
                        "Document invariants with // SAFETY: before unsafe blocks."
                    ),
                ),
            )
    return violations

RustCloneOverheadDetector

RustCloneOverheadDetector()

Bases: ViolationDetector[RustCloneOverheadConfig]

Detects excessive .clone() calls that undermine Rust's zero-cost abstraction goal.

Cloning performs a deep copy, which can be expensive for heap-allocated types like String or Vec. Idiomatic Rust prefers borrowing or Cow<T> to avoid unnecessary allocations. This detector counts .clone() invocations via regex and flags files that exceed the configured ceiling.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustCloneOverheadConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustCloneOverheadConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustCloneOverheadConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    count = len(re.findall(r"\.clone\s*\(", context.code))
    if count > config.max_clone_calls:
        violations.append(
            self.build_violation(
                config,
                contains="clone",
                index=0,
                suggestion="Prefer borrowing or Cow<T> over cloning in hot paths.",
            ),
        )
    return violations

RustErrorHandlingDetector

RustErrorHandlingDetector()

Bases: ViolationDetector[RustErrorHandlingConfig]

Flags functions that use Result without propagating errors and detects panic! abuse.

Rust's error model relies on Result<T, E> with the ? operator for ergonomic propagation. Functions that declare Result returns but never use ? likely swallow errors silently. Additionally, panic! in library code is an anti-pattern because callers cannot recover. This detector checks both conditions via regex scans.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustErrorHandlingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustErrorHandlingConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustErrorHandlingConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    if (
        config.detect_unhandled_results
        and re.search(r"\bResult<", context.code)
        and not re.search(r"\?", context.code)
    ):
        violations.append(
            self.build_violation(
                config,
                contains="Result",
                index=0,
                suggestion="Propagate errors with ? or handle Result explicitly.",
            ),
        )
    panic_count = len(re.findall(r"\bpanic!\s*\(", context.code))
    if panic_count > config.max_panics:
        violations.append(
            self.build_violation(
                config,
                contains="panic",
                index=0,
                suggestion="Avoid panic! in library code; return Result instead.",
            ),
        )
    return violations

RustTypeSafetyDetector

RustTypeSafetyDetector()

Bases: ViolationDetector[RustTypeSafetyConfig]

Flags structs that use raw primitive types instead of domain-specific newtypes.

Rust's type system is strong enough to prevent entire categories of bugs via newtypes (e.g., struct UserId(u64) instead of bare u64). Raw primitives in struct fields lose semantic meaning and allow accidental mixing of unrelated values. This detector scans struct bodies for configured primitive types and suggests wrapping them in dedicated newtypes or enums.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustTypeSafetyConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustTypeSafetyConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustTypeSafetyConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    types_pattern = "|".join(re.escape(t) for t in config.primitive_types)
    if not types_pattern:
        return violations
    struct_pattern = re.compile(r"struct\s+\w+\s*\{(?P<body>[^}]*)\}", re.DOTALL)
    for match in struct_pattern.finditer(context.code):
        body = match.group("body")
        if type_match := re.search(rf":\s*(?P<typ>{types_pattern})\b", body):
            violations.append(
                self.build_violation(
                    config,
                    contains=type_match["typ"],
                    index=0,
                    suggestion=(
                        "Introduce newtypes or enums for domain-specific values instead "
                        "of raw primitives."
                    ),
                ),
            )
            break
    return violations

RustIteratorPreferenceDetector

RustIteratorPreferenceDetector()

Bases: ViolationDetector[RustIteratorPreferenceConfig]

Flags excessive manual loops where iterator adapters would be more idiomatic.

Rust's iterator combinators (map, filter, fold, etc.) are zero-cost abstractions that the compiler can optimize as well as hand-written loops, while being more expressive and less error-prone. This detector counts for and while loops and flags files that exceed the configured maximum, encouraging iterator-based transformations instead.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustIteratorPreferenceConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustIteratorPreferenceConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustIteratorPreferenceConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    loop_count = len(re.findall(r"\bfor\s+\w+\s+in\b", context.code)) + len(
        re.findall(r"\bwhile\b", context.code),
    )
    if loop_count > config.max_loops:
        return [
            self.build_violation(
                config,
                contains="for",
                index=0,
                suggestion="Prefer iterator adapters (map/filter) over manual loops.",
            ),
        ]
    return []

RustMustUseDetector

RustMustUseDetector()

Bases: ViolationDetector[RustMustUseConfig]

Detects Result-returning code that omits the #[must_use] attribute.

When a function returns Result but the caller ignores the return value, errors are silently discarded. The #[must_use] attribute causes a compiler warning when a return value is unused, making neglected errors visible at build time. This detector flags files that contain Result< without any #[must_use] annotation.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustMustUseConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustMustUseConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustMustUseConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "Result<" in context.code and "#[must_use]" not in context.code:
        return [
            self.build_violation(
                config,
                contains="Result",
                index=0,
                suggestion="Annotate important return types with #[must_use].",
            ),
        ]
    return []

RustDebugDeriveDetector

RustDebugDeriveDetector()

Bases: ViolationDetector[RustDebugDeriveConfig]

Ensures public structs derive Debug for ergonomic logging and diagnostics.

In Rust, #[derive(Debug)] enables {:?} formatting, which is essential for logging, test assertions, and interactive debugging. Public structs without Debug force consumers to work blindly with opaque values. This detector checks whether files containing pub struct also include #[derive(Debug)] somewhere.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustDebugDeriveConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustDebugDeriveConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustDebugDeriveConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "pub struct" in context.code and "#[derive(Debug)]" not in context.code:
        return [
            self.build_violation(
                config,
                contains="Debug",
                index=0,
                suggestion="Derive Debug for public structs with #[derive(Debug)].",
            ),
        ]
    return []

RustNewtypePatternDetector

RustNewtypePatternDetector()

Bases: ViolationDetector[RustNewtypePatternConfig]

Flags type aliases to primitives that should be tuple-struct newtypes.

A type Alias = u64 creates a transparent synonym with no type safety: a UserId and a PostId are freely interchangeable. A tuple-struct newtype (struct UserId(u64)) is a distinct type the compiler enforces at every call site. This detector scans for type X = <primitive> patterns and suggests newtypes instead.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustNewtypePatternConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustNewtypePatternConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustNewtypePatternConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if types_pattern := "|".join(re.escape(t) for t in config.primitive_types):
        return (
            [
                self.build_violation(
                    config,
                    contains="type",
                    index=0,
                    suggestion="Prefer tuple struct newtypes over type aliases.",
                ),
            ]
            if re.search(rf"type\s+\w+\s*=\s*(?:{types_pattern})\b", context.code)
            else []
        )
    return []

RustStdTraitsDetector

RustStdTraitsDetector()

Bases: ViolationDetector[RustStdTraitsConfig]

Detects structs that lack standard trait implementations like From or Display.

Implementing standard library traits (From, Into, Default, Display) lets a struct participate in Rust's ecosystem idioms — conversions, default construction, and user-facing formatting — without custom methods. This detector flags files containing struct definitions that have no impl blocks for any of these key traits.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustStdTraitsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustStdTraitsConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustStdTraitsConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if "struct" in context.code and not re.search(
        r"impl\s+(From|Into|Default|Display)",
        context.code,
    ):
        return [
            self.build_violation(
                config,
                contains="impl",
                index=0,
                suggestion="Implement standard traits like From, Default, or Display.",
            ),
        ]
    return []

RustEnumOverBoolDetector

RustEnumOverBoolDetector()

Bases: ViolationDetector[RustEnumOverBoolConfig]

Flags structs with too many boolean fields that should be expressed as enums.

Multiple bool fields in a struct create combinatorial state explosions and make call sites confusing (new(true, false, true)). An enum with named variants (enum Mode { Read, Write }) is self-documenting and the compiler can verify exhaustive matching. This detector counts : bool annotations and flags files that exceed the configured maximum.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustEnumOverBoolConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustEnumOverBoolConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustEnumOverBoolConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    bool_fields = len(re.findall(r":\s*bool\b", context.code))
    if bool_fields > config.max_bool_fields:
        return [
            self.build_violation(
                config,
                contains="bool",
                index=0,
                suggestion="Use enums instead of boolean flags for state.",
            ),
        ]
    return []

RustLifetimeUsageDetector

RustLifetimeUsageDetector()

Bases: ViolationDetector[RustLifetimeUsageConfig]

Flags excessive explicit lifetime annotations where elision would suffice.

Rust's lifetime elision rules handle the majority of borrow cases automatically. Overusing explicit lifetimes ('a, 'static) adds visual noise and cognitive overhead without improving safety. This detector counts explicit lifetime parameters and 'static annotations via regex and flags files that exceed the configured threshold.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustLifetimeUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustLifetimeUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustLifetimeUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    lifetimes = len(re.findall(r"<\s*'\w+", context.code)) + len(
        re.findall(r"'static", context.code),
    )
    if lifetimes > config.max_explicit_lifetimes:
        return [
            self.build_violation(
                config,
                contains="lifetime",
                index=0,
                suggestion="Prefer elided lifetimes unless explicit ones are required.",
            ),
        ]
    return []

RustInteriorMutabilityDetector

RustInteriorMutabilityDetector()

Bases: ViolationDetector[RustInteriorMutabilityConfig]

Detects Rc<RefCell<T>> and Arc<Mutex<T>> patterns that signal design issues.

Interior mutability types let you mutate data behind shared references, but Rc<RefCell<T>> panics on borrow violations at runtime and Arc<Mutex<T>> risks deadlocks. Frequent use of these wrappers often indicates that ownership boundaries need rethinking. This detector scans for both patterns via regex and flags their presence.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: RustInteriorMutabilityConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustInteriorMutabilityConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (RustInteriorMutabilityConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if re.search(r"Rc<\s*RefCell|Arc<\s*Mutex", context.code):
        return [
            self.build_violation(
                config,
                contains="RefCell",
                index=0,
                suggestion="Avoid Rc<RefCell> or Arc<Mutex> unless required.",
            ),
        ]
    return []

RustSendSyncDetector

RustSendSyncDetector()

Bases: ViolationDetector[RustSendSyncConfig]

Flags unsafe Send/Sync implementations without SAFETY comments.

unsafe impl Send or unsafe impl Sync should always be accompanied by a // SAFETY: comment explaining the soundness justification.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect unsafe Send/Sync without safety comments.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: RustSendSyncConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustSendSyncConfig,
) -> list[Violation]:
    """Detect unsafe Send/Sync without safety comments.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (RustSendSyncConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    lines = context.code.splitlines()
    violations: list[Violation] = []
    for i, line in enumerate(lines):
        if re.search(r"unsafe\s+impl\s+(Send|Sync)", line):
            prev = lines[i - 1].strip() if i > 0 else ""
            if "SAFETY:" not in prev:
                violations.append(
                    self.build_violation(
                        config,
                        contains="unsafe impl",
                        suggestion="Add a // SAFETY: comment before unsafe Send/Sync impls.",
                    ),
                )
    return violations

RustErrorTraitsDetector

RustErrorTraitsDetector()

Bases: ViolationDetector[RustErrorTraitsConfig]

Flags error types that do not implement std::error::Error.

Custom error structs/enums should implement std::error::Error and Display so they integrate with the standard error ecosystem.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect error types missing std::error::Error impls.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: RustErrorTraitsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustErrorTraitsConfig,
) -> list[Violation]:
    """Detect error types missing std::error::Error impls.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (RustErrorTraitsConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(r"(struct|enum)\s+\w*Error", context.code) and not re.search(
        r"impl.*(std::error::Error|Error\s+for)",
        context.code,
    ):
        return [
            self.build_violation(
                config,
                contains="Error type",
                suggestion="Error types should implement std::error::Error and Display.",
            ),
        ]
    return []

RustNamingDetector

RustNamingDetector()

Bases: ViolationDetector[RustNamingConfig]

Flags functions using camelCase instead of snake_case.

RFC 430 mandates snake_case for function names in Rust.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect camelCase function names violating RFC 430.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: RustNamingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustNamingConfig,
) -> list[Violation]:
    """Detect camelCase function names violating RFC 430.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (RustNamingConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(r"fn\s+[a-z]+[A-Z]", context.code):
        return [
            self.build_violation(
                config,
                contains="naming",
                suggestion="Follow Rust naming conventions (RFC 430): snake_case for functions.",
            ),
        ]
    return []

RustDefaultImplDetector

RustDefaultImplDetector()

Bases: ViolationDetector[RustDefaultImplConfig]

Flags public structs that lack a Default implementation.

Public structs with an obvious default state should implement Default so callers can construct them ergonomically.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect public structs without Default derivation.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: RustDefaultImplConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustDefaultImplConfig,
) -> list[Violation]:
    """Detect public structs without Default derivation.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (RustDefaultImplConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    violations: list[Violation] = []
    lines = context.code.splitlines()
    for i, line in enumerate(lines):
        if re.search(r"pub\s+struct\s+\w+", line):
            preceding = "\n".join(lines[max(0, i - 5) : i])
            if not re.search(r"#\[derive\(.*Default", preceding):
                violations.append(
                    self.build_violation(
                        config,
                        contains="pub struct",
                        suggestion="Implement Default when there's an obvious default state.",
                    ),
                )
    return violations

RustFromIntoDetector

RustFromIntoDetector()

Bases: ViolationDetector[RustFromIntoConfig]

Flags ad-hoc conversion functions that should use From/Into traits.

Idiomatic Rust uses From/Into traits for type conversions rather than standalone from_*/to_*/into_* functions.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect ad-hoc conversion functions missing From/Into impls.

PARAMETER DESCRIPTION
context

Analysis context with source code.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: RustFromIntoConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Detected violations.

Source code in src/mcp_zen_of_languages/languages/rust/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: RustFromIntoConfig,
) -> list[Violation]:
    """Detect ad-hoc conversion functions missing From/Into impls.

    Args:
        context (AnalysisContext): Analysis context with source code.
        config (RustFromIntoConfig): Detector configuration.

    Returns:
        list[Violation]: Detected violations.
    """
    if re.search(
        r"fn\s+(from_\w+|to_\w+|into_\w+)\s*\(",
        context.code,
    ) and not re.search(r"impl\s+From", context.code):
        return [
            self.build_violation(
                config,
                contains="conversion function",
                suggestion="Use From/Into traits for type conversions.",
            ),
        ]
    return []

TOML

mcp_zen_of_languages.languages.toml.detectors

Detectors for TOML file quality, enforcing table structure, key conventions, and value formatting.

Classes

TomlNoInlineTablesDetector

TomlNoInlineTablesDetector()

Bases: ViolationDetector[TomlNoInlineTablesConfig], LocationHelperMixin

Flags inline table syntax (key = { ... }) that should use full table sections.

Inline tables are compact but become hard to read and diff when they grow beyond a few key-value pairs. The TOML specification intentionally limits inline tables to a single line, so complex structures are better expressed as standard [table] sections for clarity and version-control friendliness.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'toml-001' identifying the inline tables detector.

RETURNS DESCRIPTION
str

The 'toml-001' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Scan for = { patterns indicating inline table assignments.

PARAMETER DESCRIPTION
context

Analysis context holding the raw TOML text.

TYPE: AnalysisContext

config

Inline table thresholds and violation message templates.

TYPE: TomlNoInlineTablesConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per line containing an inline table.

Source code in src/mcp_zen_of_languages/languages/toml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TomlNoInlineTablesConfig,
) -> list[Violation]:
    """Scan for ``= {`` patterns indicating inline table assignments.

    Args:
        context (AnalysisContext): Analysis context holding the raw TOML text.
        config (TomlNoInlineTablesConfig): Inline table thresholds and violation message templates.

    Returns:
        list[Violation]: One violation per line containing an inline table.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="{",
            location=Location(line=idx, column=line.find("{") + 1),
            suggestion="Prefer full tables over inline tables.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r"=\s*\{", line)
    ]
    return violations

TomlDuplicateKeysDetector

TomlDuplicateKeysDetector()

Bases: ViolationDetector[TomlDuplicateKeysConfig], LocationHelperMixin

Catches repeated bare keys within the same scope of a TOML file.

TOML forbids duplicate keys at the same level; most parsers will either error or silently use the last value. This detector performs a linear scan of top-level assignments (outside [table] headers) to surface duplicates before they cause parser failures or data loss.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'toml-002' identifying the duplicate keys detector.

RETURNS DESCRIPTION
str

The 'toml-002' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Track seen keys and flag any that appear more than once at the same level.

PARAMETER DESCRIPTION
context

Analysis context holding the raw TOML text.

TYPE: AnalysisContext

config

Duplicate key thresholds and violation message templates.

TYPE: TomlDuplicateKeysConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per duplicate key occurrence.

Source code in src/mcp_zen_of_languages/languages/toml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TomlDuplicateKeysConfig,
) -> list[Violation]:
    """Track seen keys and flag any that appear more than once at the same level.

    Args:
        context (AnalysisContext): Analysis context holding the raw TOML text.
        config (TomlDuplicateKeysConfig): Duplicate key thresholds and violation message templates.

    Returns:
        list[Violation]: One violation per duplicate key occurrence.
    """
    violations: list[Violation] = []
    seen: set[str] = set()
    for idx, line in enumerate(context.code.splitlines(), start=1):
        if line.strip().startswith("["):
            continue
        match = re.match(r"^\s*([A-Za-z0-9_.-]+)\s*=", line)
        if not match:
            continue
        key = match[1]
        if key in seen:
            violations.append(
                self.build_violation(
                    config,
                    contains=key,
                    location=Location(line=idx, column=1),
                    suggestion="Avoid duplicate keys in TOML files.",
                ),
            )
        seen.add(key)
    return violations

TomlLowercaseKeysDetector

TomlLowercaseKeysDetector()

Bases: ViolationDetector[TomlLowercaseKeysConfig], LocationHelperMixin

Enforces lowercase key names throughout the TOML document.

TOML keys are case-sensitive, so Name and name are distinct keys. Mixing cases within a project invites hard-to-spot bugs where a consumer references the wrong variant. Standardising on lowercase (with hyphens or underscores for word separation) improves predictability and grep-ability.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'toml-003' identifying the lowercase keys detector.

RETURNS DESCRIPTION
str

The 'toml-003' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Scan key assignments and flag any containing uppercase characters.

PARAMETER DESCRIPTION
context

Analysis context holding the raw TOML text.

TYPE: AnalysisContext

config

Lowercase key thresholds and violation message templates.

TYPE: TomlLowercaseKeysConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per key that contains uppercase letters.

Source code in src/mcp_zen_of_languages/languages/toml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TomlLowercaseKeysConfig,
) -> list[Violation]:
    """Scan key assignments and flag any containing uppercase characters.

    Args:
        context (AnalysisContext): Analysis context holding the raw TOML text.
        config (TomlLowercaseKeysConfig): Lowercase key thresholds and violation message templates.

    Returns:
        list[Violation]: One violation per key that contains uppercase letters.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.match(r"^\s*([A-Za-z0-9_.-]+)\s*=", line)
        if not match:
            continue
        key = match[1]
        if any(char.isupper() for char in key):
            violations.append(
                self.build_violation(
                    config,
                    contains=key,
                    location=Location(line=idx, column=1),
                    suggestion="Use lowercase keys for TOML consistency.",
                ),
            )
    return violations

TomlTrailingCommasDetector

TomlTrailingCommasDetector()

Bases: ViolationDetector[TomlTrailingCommasConfig], LocationHelperMixin

Detects trailing commas inside TOML arrays and inline tables.

Unlike JSON5 or JavaScript, TOML does not permit trailing commas in arrays or inline tables. Their presence causes parser errors, and some editors may silently insert them during copy-paste. This detector catches the pattern early to prevent downstream parsing failures.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'toml-004' identifying the trailing commas detector.

RETURNS DESCRIPTION
str

The 'toml-004' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Search for comma-then-closing-bracket patterns on each line.

PARAMETER DESCRIPTION
context

Analysis context holding the raw TOML text.

TYPE: AnalysisContext

config

Trailing comma thresholds and violation message templates.

TYPE: TomlTrailingCommasConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per line containing a trailing comma.

Source code in src/mcp_zen_of_languages/languages/toml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TomlTrailingCommasConfig,
) -> list[Violation]:
    """Search for comma-then-closing-bracket patterns on each line.

    Args:
        context (AnalysisContext): Analysis context holding the raw TOML text.
        config (TomlTrailingCommasConfig): Trailing comma thresholds and violation message templates.

    Returns:
        list[Violation]: One violation per line containing a trailing comma.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="trailing comma",
            location=Location(line=idx, column=1),
            suggestion="Remove trailing commas for TOML clarity.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if re.search(r",\s*[\]\}]", line)
    ]
    return violations

TomlCommentClarityDetector

TomlCommentClarityDetector()

Bases: ViolationDetector[TomlCommentClarityConfig], LocationHelperMixin

Ensures TOML files with non-trivial configuration include explanatory comments.

Configuration files often contain "magic" values whose purpose is unclear without context. A TOML file that assigns values but lacks any # comments forces readers to guess intent. This detector compares the number of comment lines against a configurable minimum and flags under-documented files.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'toml-005' identifying the comment clarity detector.

RETURNS DESCRIPTION
str

The 'toml-005' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Count comment lines and flag the file when fewer than min_comment_lines exist.

PARAMETER DESCRIPTION
context

Analysis context holding the raw TOML text.

TYPE: AnalysisContext

config

Comment clarity thresholds including min_comment_lines.

TYPE: TomlCommentClarityConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation when comment coverage is below the threshold.

Source code in src/mcp_zen_of_languages/languages/toml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TomlCommentClarityConfig,
) -> list[Violation]:
    """Count comment lines and flag the file when fewer than *min_comment_lines* exist.

    Args:
        context (AnalysisContext): Analysis context holding the raw TOML text.
        config (TomlCommentClarityConfig): Comment clarity thresholds including ``min_comment_lines``.

    Returns:
        list[Violation]: A single violation when comment coverage is below the threshold.
    """
    comments = [
        line for line in context.code.splitlines() if line.strip().startswith("#")
    ]
    if len(comments) < config.min_comment_lines and " = " in context.code:
        return [
            self.build_violation(
                config,
                contains="comment",
                location=Location(line=1, column=1),
                suggestion="Add comments for magic values.",
            ),
        ]
    return []

TomlOrderDetector

TomlOrderDetector()

Bases: ViolationDetector[TomlOrderConfig], LocationHelperMixin

Detects poorly grouped table sections that are separated by excessive whitespace.

Logically related TOML tables should appear near each other so readers can scan the file top-to-bottom without jumping. When two consecutive [table] headers are separated by more than ten lines, this detector flags the gap to encourage tighter grouping and optional blank-line separators.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'toml-006' identifying the table order detector.

RETURNS DESCRIPTION
str

The 'toml-006' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Measure line gaps between consecutive [table] headers and flag large separations.

PARAMETER DESCRIPTION
context

Analysis context holding the raw TOML text.

TYPE: AnalysisContext

config

Table order thresholds and violation message templates.

TYPE: TomlOrderConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation when any inter-table gap exceeds ten lines.

Source code in src/mcp_zen_of_languages/languages/toml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TomlOrderConfig,
) -> list[Violation]:
    """Measure line gaps between consecutive ``[table]`` headers and flag large separations.

    Args:
        context (AnalysisContext): Analysis context holding the raw TOML text.
        config (TomlOrderConfig): Table order thresholds and violation message templates.

    Returns:
        list[Violation]: A single violation when any inter-table gap exceeds ten lines.
    """
    table_headers = [
        idx
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if line.strip().startswith("[") and line.strip().endswith("]")
    ]
    if len(table_headers) >= MIN_TABLE_HEADERS_FOR_GAP:
        gaps = [b - a for a, b in itertools.pairwise(table_headers)]
        if any(gap > MAX_TABLE_GAP_LINES for gap in gaps):
            return [
                self.build_violation(
                    config,
                    contains="table order",
                    location=Location(line=table_headers[0], column=1),
                    suggestion="Group related TOML tables together.",
                ),
            ]
    return []

TomlIsoDatetimeDetector

TomlIsoDatetimeDetector()

Bases: ViolationDetector[TomlIsoDatetimeConfig], LocationHelperMixin

Enforces ISO 8601 datetime formatting in quoted TOML string values.

TOML supports native datetime literals, but quoted strings with locale-specific formats like MM/DD/YYYY are still common in hand-edited files. This detector identifies such patterns and recommends ISO 8601 (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SSZ) for consistency and unambiguous parsing.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'toml-007' identifying the ISO datetime detector.

RETURNS DESCRIPTION
str

The 'toml-007' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Search quoted string values for non-ISO date patterns like MM/DD/YYYY.

PARAMETER DESCRIPTION
context

Analysis context holding the raw TOML text.

TYPE: AnalysisContext

config

ISO datetime thresholds and violation message templates.

TYPE: TomlIsoDatetimeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations for the first non-ISO date string found.

Source code in src/mcp_zen_of_languages/languages/toml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TomlIsoDatetimeConfig,
) -> list[Violation]:
    """Search quoted string values for non-ISO date patterns like ``MM/DD/YYYY``.

    Args:
        context (AnalysisContext): Analysis context holding the raw TOML text.
        config (TomlIsoDatetimeConfig): ISO datetime thresholds and violation message templates.

    Returns:
        list[Violation]: Violations for the first non-ISO date string found.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.search(r"=\s*\"([^\"]+)\"", line)
        if not match:
            continue
        value = match[1]
        if re.fullmatch(r"\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}Z?", value):
            continue
        if re.fullmatch(r"\d{4}-\d{2}-\d{2}", value):
            continue
        if re.search(r"\d{2}/\d{2}/\d{4}", value):
            violations.append(
                self.build_violation(
                    config,
                    contains=value,
                    location=Location(line=idx, column=1),
                    suggestion="Use ISO 8601 date/time strings.",
                ),
            )
            break
    return violations

TomlFloatIntegerDetector

TomlFloatIntegerDetector()

Bases: ViolationDetector[TomlFloatIntegerConfig], LocationHelperMixin

Flags float literals ending in .0 that should be plain integers.

Writing count = 5.0 when the value is conceptually an integer introduces unnecessary type ambiguity. Downstream consumers may treat it as a float, leading to unexpected behaviour in integer-only contexts. This detector identifies N.0 patterns and suggests using the integer form instead.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'toml-008' identifying the float/integer precision detector.

RETURNS DESCRIPTION
str

The 'toml-008' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Scan assignments for numeric values matching the N.0 pattern.

PARAMETER DESCRIPTION
context

Analysis context holding the raw TOML text.

TYPE: AnalysisContext

config

Float/integer thresholds and violation message templates.

TYPE: TomlFloatIntegerConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation for the first .0 float found.

Source code in src/mcp_zen_of_languages/languages/toml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TomlFloatIntegerConfig,
) -> list[Violation]:
    """Scan assignments for numeric values matching the ``N.0`` pattern.

    Args:
        context (AnalysisContext): Analysis context holding the raw TOML text.
        config (TomlFloatIntegerConfig): Float/integer thresholds and violation message templates.

    Returns:
        list[Violation]: A single violation for the first ``.0`` float found.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        if match := re.search(r"=\s*([0-9]+)\.0\b", line):
            violations.append(
                self.build_violation(
                    config,
                    contains=match[0],
                    location=Location(line=idx, column=1),
                    suggestion="Use integers instead of floats ending in .0.",
                ),
            )
            break
    return violations

TypeScript

mcp_zen_of_languages.languages.typescript.detectors

Rule detectors for typescript code quality and architecture checks.

Classes

TsAnyUsageDetector

TsAnyUsageDetector()

Bases: ViolationDetector[TsAnyUsageConfig], LocationHelperMixin

Detects excessive use of the any type that undermines TypeScript's value.

The any type disables all type checking for a value, silently propagating unsafety through every expression it touches. This detector counts any annotations via detect_ts_any_usage and flags files that exceed the configured threshold, encouraging the use of unknown, generics, or concrete types instead.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsAnyUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsAnyUsageConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsAnyUsageConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    finding = detect_ts_any_usage(context.code)
    if finding.count > config.max_any_usages:
        violations.append(
            self.build_violation(
                config,
                contains="any",
                index=0,
                suggestion="Use unknown or specific types instead of any.",
            ),
        )
    return violations

TsStrictModeDetector

TsStrictModeDetector()

Bases: ViolationDetector[TsStrictModeConfig]

Checks whether strict compiler options are enabled in the project.

TypeScript's strict flag activates strictNullChecks, noImplicitAny, and other safety options that catch common bugs at compile time. Without strict mode, TypeScript behaves almost like plain JavaScript, making the type system advisory rather than enforced. This detector raises a violation when strict mode is required by configuration but not detected in the source.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(_context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
_context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsStrictModeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    _context: AnalysisContext,
    config: TsStrictModeConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        _context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsStrictModeConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    if config.require_strict:
        violations.append(
            self.build_violation(
                config,
                contains="strict",
                index=0,
                suggestion="Enable strict compiler options in tsconfig.",
            ),
        )
    return violations

TsInterfacePreferenceDetector

TsInterfacePreferenceDetector()

Bases: ViolationDetector[TsInterfacePreferenceConfig], LocationHelperMixin

Flags object-shaped type aliases that should be interfaces instead.

In TypeScript, interface declarations are open for extension via declaration merging and produce clearer error messages than type aliases for object shapes. This detector uses detect_ts_object_type_aliases to count type Foo = { ... } patterns and flags files that exceed the configured limit, encouraging the use of interface for plain object contracts.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsInterfacePreferenceConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsInterfacePreferenceConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsInterfacePreferenceConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    finding = detect_ts_object_type_aliases(context.code)
    if finding.count > config.max_object_type_aliases:
        violations.append(
            self.build_violation(
                config,
                contains="Type aliases",
                index=0,
                suggestion="Prefer interfaces for object shapes.",
            ),
        )
    return violations

TsReturnTypeDetector

TsReturnTypeDetector()

Bases: ViolationDetector[TsReturnTypeConfig], LocationHelperMixin

Flags exported functions that lack explicit return type annotations.

When functions omit return types, TypeScript infers them, which can silently widen the contract and break callers after refactoring. Explicit return types serve as documentation and a stability guarantee at API boundaries. This detector uses detect_ts_missing_return_types to scan for exported functions without a declared return type.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsReturnTypeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsReturnTypeConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsReturnTypeConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    if not config.require_return_types:
        return []
    violations: list[Violation] = []
    finding = detect_ts_missing_return_types(context.code)
    if finding.count > 0:
        violations.append(
            self.build_violation(
                config,
                contains="return type",
                index=0,
                suggestion="Add explicit return types for exported functions.",
            ),
        )
    return violations

TsReadonlyDetector

TsReadonlyDetector()

Bases: ViolationDetector[TsReadonlyConfig], LocationHelperMixin

Detects insufficient use of readonly for immutable properties and arrays.

Marking properties and array types as readonly prevents accidental mutation, a common source of bugs in shared state. This detector counts readonly annotations via detect_ts_readonly_usage and flags files where the count falls below the configured minimum, nudging authors toward immutability by default.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsReadonlyConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsReadonlyConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsReadonlyConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    finding = detect_ts_readonly_usage(context.code)
    if (
        config.require_readonly_properties
        and finding.count < config.min_readonly_occurrences
    ):
        violations.append(
            self.build_violation(
                config,
                contains="readonly",
                index=0,
                suggestion="Use readonly for immutable properties and arrays.",
            ),
        )
    return violations

TsTypeGuardDetector

TsTypeGuardDetector()

Bases: ViolationDetector[TsTypeGuardConfig], LocationHelperMixin

Flags overuse of type assertions (as T) instead of user-defined type guards.

Type assertions bypass the compiler's narrowing logic and can mask runtime type mismatches. User-defined type guards (x is Foo) let TypeScript narrow types safely within conditional branches. This detector uses detect_ts_type_assertions to count as casts and flags files that exceed the configured ceiling.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsTypeGuardConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsTypeGuardConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsTypeGuardConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    finding = detect_ts_type_assertions(context.code)
    if finding.count > config.max_type_assertions:
        violations.append(
            self.build_violation(
                config,
                contains="assertions",
                index=0,
                suggestion="Prefer user-defined type guards over assertions.",
            ),
        )
    return violations

TsUtilityTypesDetector

TsUtilityTypesDetector()

Bases: ViolationDetector[TsUtilityTypesConfig], LocationHelperMixin

Detects missed opportunities to use built-in utility types like Partial or Pick.

TypeScript ships with utility types (Partial<T>, Readonly<T>, Pick<T, K>, etc.) that express common type transformations concisely. When a codebase defines many object type aliases but rarely uses utility types, authors are likely duplicating structure that could be derived. This detector cross-checks utility-type usage against object-alias counts and flags the gap.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsUtilityTypesConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsUtilityTypesConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsUtilityTypesConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    utility = detect_ts_utility_types(context.code)
    object_aliases = detect_ts_object_type_aliases(context.code)
    if (
        utility.count < config.min_utility_type_usage
        and object_aliases.count >= config.min_object_type_aliases
    ):
        violations.append(
            self.build_violation(
                config,
                contains="utility",
                index=0,
                suggestion="Use built-in utility types for transformations.",
            ),
        )
    return violations

TsNonNullAssertionDetector

TsNonNullAssertionDetector()

Bases: ViolationDetector[TsNonNullAssertionConfig], LocationHelperMixin

Flags excessive non-null assertion operators (!) that silence null safety.

The postfix ! operator tells TypeScript to trust that a value is neither null nor undefined, but it offers no runtime protection. Chained assertions like obj!.prop! are especially dangerous. This detector combines results from detect_ts_non_null_assertions with a regex scan for chained patterns and flags files that exceed the configured limit.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsNonNullAssertionConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsNonNullAssertionConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsNonNullAssertionConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    finding = detect_ts_non_null_assertions(context.code)
    chain_count = len(re.findall(r"\w+!\.\w+!", context.code))
    if finding.count + chain_count > config.max_non_null_assertions:
        violations.append(
            self.build_violation(
                config,
                contains="Non-null",
                index=1,
                suggestion="Handle null/undefined via checks instead of non-null assertions.",
            ),
        )
    return violations

TsEnumConstDetector

TsEnumConstDetector()

Bases: ViolationDetector[TsEnumConstConfig], LocationHelperMixin

Detects plain object literals used as constants instead of enums or as const.

Plain objects masquerading as enumerations lose TypeScript's exhaustiveness checking and allow arbitrary string or number values to slip through. Using enum or as const assertions gives the compiler a closed set of values it can verify at every usage site. This detector uses detect_ts_plain_enum_objects to count constant-like object patterns and flags files above the threshold.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsEnumConstConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsEnumConstConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsEnumConstConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    finding = detect_ts_plain_enum_objects(context.code)
    if finding.count > config.max_plain_enum_objects:
        violations.append(
            self.build_violation(
                config,
                contains="Plain objects",
                index=0,
                suggestion="Use enums or const assertions for constants.",
            ),
        )
    return violations

TsUnknownOverAnyDetector

TsUnknownOverAnyDetector()

Bases: ViolationDetector[TsUnknownOverAnyConfig], LocationHelperMixin

Flags codebases that use any without ever using the safer unknown alternative.

unknown is the type-safe counterpart of any: it accepts every value but requires narrowing before use, catching mistakes that any would silently allow. This detector checks whether any annotations appear above the configured ceiling while unknown is entirely absent, indicating that authors may not be aware of the safer option.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier used by registry wiring.

RETURNS DESCRIPTION
str

Identifier string consumed by callers.

TYPE: str

Functions
detect
detect(context, config)

Detect violations for the current analysis context.

PARAMETER DESCRIPTION
context

Analysis context containing source text and intermediate metrics.

TYPE: AnalysisContext

config

Typed detector or analyzer configuration that controls thresholds.

TYPE: TsUnknownOverAnyConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations detected for the analyzed context.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsUnknownOverAnyConfig,
) -> list[Violation]:
    """Detect violations for the current analysis context.

    Args:
        context (AnalysisContext): Analysis context containing source text and intermediate metrics.
        config (TsUnknownOverAnyConfig): Typed detector or analyzer configuration that controls thresholds.

    Returns:
        list[Violation]: Violations detected for the analyzed context.
    """
    violations: list[Violation] = []
    finding = detect_ts_unknown_over_any(context.code)
    if (
        finding.any_count > config.max_any_for_unknown
        and finding.unknown_count == 0
    ):
        violations.append(
            self.build_violation(
                config,
                contains="any",
                index=0,
                suggestion="Prefer unknown for uncertain types.",
            ),
        )
    return violations

TsOptionalChainingDetector

TsOptionalChainingDetector()

Bases: ViolationDetector[TsOptionalChainingConfig], LocationHelperMixin

Detects manual null-check chains replaceable by optional chaining (?.).

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect manual null-check chain violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsOptionalChainingConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsOptionalChainingConfig,
) -> list[Violation]:
    """Detect manual null-check chain violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsOptionalChainingConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    finding = detect_ts_optional_chaining(context.code)
    if finding.count > config.max_manual_null_checks:
        violations.append(
            self.build_violation(
                config,
                contains="&&",
                index=0,
                suggestion="Use optional chaining (?.) instead of manual null checks.",
            ),
        )
    return violations

TsIndexLoopDetector

TsIndexLoopDetector()

Bases: ViolationDetector[TsIndexLoopConfig], LocationHelperMixin

Detects C-style index-based for loops replaceable by for-of or array methods.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect index-loop violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsIndexLoopConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsIndexLoopConfig,
) -> list[Violation]:
    """Detect index-loop violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsIndexLoopConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    finding = detect_ts_index_loops(context.code)
    if finding.count > config.max_index_loops:
        violations.append(
            self.build_violation(
                config,
                contains="for",
                index=0,
                suggestion="Prefer for-of or array methods over index loops.",
            ),
        )
    return violations

TsPromiseChainDetector

TsPromiseChainDetector()

Bases: ViolationDetector[TsPromiseChainConfig], LocationHelperMixin

Detects raw .then() promise chains replaceable by async/await.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect promise chain violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsPromiseChainConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsPromiseChainConfig,
) -> list[Violation]:
    """Detect promise chain violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsPromiseChainConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    finding = detect_ts_promise_chains(context.code)
    if finding.count > config.max_promise_chains:
        violations.append(
            self.build_violation(
                config,
                contains=".then(",
                index=0,
                suggestion="Prefer async/await over raw promise chains.",
            ),
        )
    return violations

TsDefaultExportDetector

TsDefaultExportDetector()

Bases: ViolationDetector[TsDefaultExportConfig], LocationHelperMixin

Detects export default statements encouraging named exports instead.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect default export violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsDefaultExportConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsDefaultExportConfig,
) -> list[Violation]:
    """Detect default export violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsDefaultExportConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    finding = detect_ts_default_exports(context.code)
    if finding.count > config.max_default_exports:
        violations.append(
            self.build_violation(
                config,
                contains="export default",
                index=0,
                suggestion="Prefer named exports for better refactoring support.",
            ),
        )
    return violations

TsCatchAllTypeDetector

TsCatchAllTypeDetector()

Bases: ViolationDetector[TsCatchAllTypeConfig], LocationHelperMixin

Detects catch-all type annotations (Object, object, {}).

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect catch-all type violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsCatchAllTypeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsCatchAllTypeConfig,
) -> list[Violation]:
    """Detect catch-all type violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsCatchAllTypeConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    finding = detect_ts_catch_all_types(context.code)
    if finding.count > config.max_catch_all_types:
        violations.append(
            self.build_violation(
                config,
                contains="Object",
                index=0,
                suggestion="Use precise types instead of Object, object, or {}.",
            ),
        )
    return violations

TsConsoleUsageDetector

TsConsoleUsageDetector()

Bases: ViolationDetector[TsConsoleUsageConfig], LocationHelperMixin

Detects console.* calls in TypeScript production code.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect console usage violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsConsoleUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsConsoleUsageConfig,
) -> list[Violation]:
    """Detect console usage violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsConsoleUsageConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    finding = detect_ts_console_usage(context.code)
    if finding.count > config.max_console_usages:
        violations.append(
            self.build_violation(
                config,
                contains="console.",
                index=0,
                suggestion="Use a proper logging framework instead of console.",
            ),
        )
    return violations

TsRequireImportDetector

TsRequireImportDetector()

Bases: ViolationDetector[TsRequireImportConfig], LocationHelperMixin

Detects require() calls encouraging ES module imports instead.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect require import violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsRequireImportConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsRequireImportConfig,
) -> list[Violation]:
    """Detect require import violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsRequireImportConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    finding = detect_ts_require_imports(context.code)
    if finding.count > config.max_require_calls:
        violations.append(
            self.build_violation(
                config,
                contains="require(",
                index=0,
                suggestion="Use ES module import/export syntax instead of require().",
            ),
        )
    return violations

TsStringConcatDetector

TsStringConcatDetector()

Bases: ViolationDetector[TsStringConcatConfig], LocationHelperMixin

Detects string concatenation patterns encouraging template literals.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect string concatenation violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsStringConcatConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsStringConcatConfig,
) -> list[Violation]:
    """Detect string concatenation violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsStringConcatConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    finding = detect_ts_string_concats(context.code)
    if finding.count > config.max_string_concats:
        violations.append(
            self.build_violation(
                config,
                contains="+",
                index=0,
                suggestion="Use template literals instead of string concatenation.",
            ),
        )
    return violations

TsAsyncAwaitDetector

TsAsyncAwaitDetector()

Bases: ViolationDetector[TsAsyncAwaitConfig], LocationHelperMixin

Detects raw .then() promise chains encouraging async/await usage.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect raw promise-chain violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsAsyncAwaitConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsAsyncAwaitConfig,
) -> list[Violation]:
    """Detect raw promise-chain violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsAsyncAwaitConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    finding = detect_ts_promise_chains(context.code)
    if finding.count > config.max_then_chains:
        violations.append(
            self.build_violation(
                config,
                contains=".then(",
                suggestion="Use async/await over raw Promise chains.",
            ),
        )
    return violations

TsForOfDetector

TsForOfDetector()

Bases: ViolationDetector[TsForOfConfig], LocationHelperMixin

Detects C-style index-based for loops encouraging for...of iteration.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect index-based loop violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsForOfConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsForOfConfig,
) -> list[Violation]:
    """Detect index-based loop violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsForOfConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    if re.search(
        r"for\s*\(\s*(let|var|const)\s+\w+\s*=\s*0\s*;\s*\w+\s*<\s*\w+\.length",
        context.code,
    ):
        violations.append(
            self.build_violation(
                config,
                contains="index loop",
                suggestion="Prefer for...of over index-based iteration.",
            ),
        )
    return violations

TsImportOrderDetector

TsImportOrderDetector()

Bases: ViolationDetector[TsImportOrderConfig], LocationHelperMixin

Detects CommonJS require() calls mixed with ES module imports.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect mixed import style violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsImportOrderConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsImportOrderConfig,
) -> list[Violation]:
    """Detect mixed import style violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsImportOrderConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    if re.search(r"\brequire\s*\(", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="require(",
                suggestion="Use consistent ES module imports; avoid mixing require().",
            ),
        )
    return violations

TsNamedExportDetector

TsNamedExportDetector()

Bases: ViolationDetector[TsNamedExportConfig], LocationHelperMixin

Detects export default usages encouraging named exports.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect default-export violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsNamedExportConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsNamedExportConfig,
) -> list[Violation]:
    """Detect default-export violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsNamedExportConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    if re.search(r"\bexport\s+default\b", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="export default",
                suggestion="Prefer named exports over default exports.",
            ),
        )
    return violations

TsNoConsoleDetector

TsNoConsoleDetector()

Bases: ViolationDetector[TsNoConsoleConfig], LocationHelperMixin

Detects console.* calls in production code.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect console statement violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsNoConsoleConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsNoConsoleConfig,
) -> list[Violation]:
    """Detect console statement violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsNoConsoleConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    if re.search(r"\bconsole\.(log|error|warn|debug|info)\s*\(", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="console.",
                suggestion="Remove console.log from production code; use a logger.",
            ),
        )
    return violations

TsObjectTypeDetector

TsObjectTypeDetector()

Bases: ViolationDetector[TsObjectTypeConfig], LocationHelperMixin

Detects generic Object/object/{} type annotations.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect generic object-type violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsObjectTypeConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsObjectTypeConfig,
) -> list[Violation]:
    """Detect generic object-type violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsObjectTypeConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    if re.search(r":\s*(Object|object|\{\s*\})(\s|;|,|\))", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="Object type",
                suggestion="Avoid Object/{}/object; use specific types or unknown.",
            ),
        )
    return violations

TsTemplateLiteralDetector

TsTemplateLiteralDetector()

Bases: ViolationDetector[TsTemplateLiteralConfig], LocationHelperMixin

Detects string concatenation patterns encouraging template literals.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return the detector identifier.

RETURNS DESCRIPTION
str

Identifier string.

TYPE: str

Functions
detect
detect(context, config)

Detect string concatenation violations.

PARAMETER DESCRIPTION
context

Analysis context.

TYPE: AnalysisContext

config

Detector configuration.

TYPE: TsTemplateLiteralConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: Violations found.

Source code in src/mcp_zen_of_languages/languages/typescript/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: TsTemplateLiteralConfig,
) -> list[Violation]:
    """Detect string concatenation violations.

    Args:
        context (AnalysisContext): Analysis context.
        config (TsTemplateLiteralConfig): Detector configuration.

    Returns:
        list[Violation]: Violations found.
    """
    violations: list[Violation] = []
    if re.search(r"""["']\s*\+\s*\w+\s*\+\s*["']""", context.code):
        violations.append(
            self.build_violation(
                config,
                contains="string concat",
                suggestion="Use template literals instead of string concatenation.",
            ),
        )
    return violations

Functions

XML

mcp_zen_of_languages.languages.xml.detectors

Detectors for XML document quality, enforcing semantic markup, namespace hygiene, and hierarchy.

Classes

XmlSemanticMarkupDetector

XmlSemanticMarkupDetector()

Bases: ViolationDetector[XmlSemanticMarkupConfig], LocationHelperMixin

Flags presentational HTML-era tags and inline style attributes in XML.

Tags like <font>, <center>, <b>, and <i> embed presentation concerns into a document that should express structure. Similarly, style="..." attributes couple layout decisions to content. This detector encourages separating presentation from semantics by using CSS or XSL stylesheets instead.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'xml-001' identifying the semantic markup detector.

RETURNS DESCRIPTION
str

The 'xml-001' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Search for presentational tags (<font>, <b>, etc.) and inline style attributes.

PARAMETER DESCRIPTION
context

Analysis context holding the raw XML markup.

TYPE: AnalysisContext

config

Semantic markup thresholds and violation message templates.

TYPE: XmlSemanticMarkupConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation when presentational elements are found.

Source code in src/mcp_zen_of_languages/languages/xml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: XmlSemanticMarkupConfig,
) -> list[Violation]:
    """Search for presentational tags (``<font>``, ``<b>``, etc.) and inline ``style`` attributes.

    Args:
        context (AnalysisContext): Analysis context holding the raw XML markup.
        config (XmlSemanticMarkupConfig): Semantic markup thresholds and violation message templates.

    Returns:
        list[Violation]: A single violation when presentational elements are found.
    """
    if re.search(r"<(font|center|b|i)(\s|>)", context.code):
        return [
            self.build_violation(
                config,
                contains="presentational tag",
                location=Location(line=1, column=1),
                suggestion="Use semantic tags instead of presentational markup.",
            ),
        ]
    if re.search(r"style=\"[^\"]+\"", context.code):
        return [
            self.build_violation(
                config,
                contains="style",
                location=Location(line=1, column=1),
                suggestion="Avoid presentation-oriented style attributes.",
            ),
        ]
    return []

XmlAttributeUsageDetector

XmlAttributeUsageDetector()

Bases: ViolationDetector[XmlAttributeUsageConfig], LocationHelperMixin

Identifies oversized attribute values that belong in child elements instead.

XML attributes are designed for short metadata—identifiers, flags, or references. When an attribute value exceeds 30 characters it typically contains data that is better expressed as element content, where it can be formatted, validated, and read more easily.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'xml-002' identifying the attribute usage detector.

RETURNS DESCRIPTION
str

The 'xml-002' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Scan for attribute values longer than 30 characters that should be child elements.

PARAMETER DESCRIPTION
context

Analysis context holding the raw XML markup.

TYPE: AnalysisContext

config

Attribute usage thresholds and violation message templates.

TYPE: XmlAttributeUsageConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation for the first oversized attribute found.

Source code in src/mcp_zen_of_languages/languages/xml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: XmlAttributeUsageConfig,
) -> list[Violation]:
    """Scan for attribute values longer than 30 characters that should be child elements.

    Args:
        context (AnalysisContext): Analysis context holding the raw XML markup.
        config (XmlAttributeUsageConfig): Attribute usage thresholds and violation message templates.

    Returns:
        list[Violation]: A single violation for the first oversized attribute found.
    """
    for idx, line in enumerate(context.code.splitlines(), start=1):
        if match := re.search(r"\w+=\"([^\"]{30,})\"", line):
            return [
                self.build_violation(
                    config,
                    contains=match[1][:10],
                    location=Location(line=idx, column=1),
                    suggestion="Move large data values into child elements.",
                ),
            ]
    return []

XmlNamespaceDetector

XmlNamespaceDetector()

Bases: ViolationDetector[XmlNamespaceConfig], LocationHelperMixin

Detects prefixed element names that lack a corresponding xmlns declaration.

Namespace prefixes like <ns:element> are meaningless without a xmlns:ns="..." binding. Missing declarations cause parser errors and make the document non-well-formed. This detector catches the oversight early so authors can add the proper namespace URI.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'xml-003' identifying the namespace declaration detector.

RETURNS DESCRIPTION
str

The 'xml-003' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Check whether prefixed elements (<prefix:tag>) have a matching xmlns binding.

PARAMETER DESCRIPTION
context

Analysis context holding the raw XML markup.

TYPE: AnalysisContext

config

Namespace thresholds and violation message templates.

TYPE: XmlNamespaceConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation when prefixed tags exist without xmlns declarations.

Source code in src/mcp_zen_of_languages/languages/xml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: XmlNamespaceConfig,
) -> list[Violation]:
    """Check whether prefixed elements (``<prefix:tag>``) have a matching ``xmlns`` binding.

    Args:
        context (AnalysisContext): Analysis context holding the raw XML markup.
        config (XmlNamespaceConfig): Namespace thresholds and violation message templates.

    Returns:
        list[Violation]: A single violation when prefixed tags exist without ``xmlns`` declarations.
    """
    has_prefix = bool(re.search(r"<\w+:\w+", context.code))
    if has_prefix and "xmlns" not in context.code:
        return [
            self.build_violation(
                config,
                contains="xmlns",
                location=Location(line=1, column=1),
                suggestion="Declare XML namespaces for prefixed elements.",
            ),
        ]
    return []

XmlValidityDetector

XmlValidityDetector()

Bases: ViolationDetector[XmlValidityConfig], LocationHelperMixin

Checks for schema or DTD references that enable structural validation.

An XML document without xsi:schemaLocation or DOCTYPE cannot be validated against a formal grammar, making it fragile and error-prone. This detector flags documents that lack any schema reference so authors can add one to enable automated validation tooling.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'xml-004' identifying the schema validity detector.

RETURNS DESCRIPTION
str

The 'xml-004' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Search for xsi:schemaLocation or DOCTYPE references in the document.

PARAMETER DESCRIPTION
context

Analysis context holding the raw XML markup.

TYPE: AnalysisContext

config

Validity thresholds and violation message templates.

TYPE: XmlValidityConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation when no schema reference is present.

Source code in src/mcp_zen_of_languages/languages/xml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: XmlValidityConfig,
) -> list[Violation]:
    """Search for ``xsi:schemaLocation`` or ``DOCTYPE`` references in the document.

    Args:
        context (AnalysisContext): Analysis context holding the raw XML markup.
        config (XmlValidityConfig): Validity thresholds and violation message templates.

    Returns:
        list[Violation]: A single violation when no schema reference is present.
    """
    if re.search(r"xsi:schemaLocation|DOCTYPE", context.code) is None:
        return [
            self.build_violation(
                config,
                contains="schema",
                location=Location(line=1, column=1),
                suggestion="Include schema references (xsi:schemaLocation or DOCTYPE).",
            ),
        ]
    return []

XmlHierarchyDetector

XmlHierarchyDetector()

Bases: ViolationDetector[XmlHierarchyConfig], LocationHelperMixin

Flags repeated sibling elements that lack a grouping parent container.

When the same tag name appears more than twice without being wrapped in a logical parent (e.g., <group>), readers struggle to understand the document's hierarchy. This detector recommends introducing a container element to clarify the relationship between repeated siblings.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'xml-005' identifying the element hierarchy detector.

RETURNS DESCRIPTION
str

The 'xml-005' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Count opening tags and flag any that repeat more than twice without a <group> wrapper.

PARAMETER DESCRIPTION
context

Analysis context holding the raw XML markup.

TYPE: AnalysisContext

config

Hierarchy thresholds and violation message templates.

TYPE: XmlHierarchyConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation when ungrouped repeated elements are found.

Source code in src/mcp_zen_of_languages/languages/xml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: XmlHierarchyConfig,
) -> list[Violation]:
    """Count opening tags and flag any that repeat more than twice without a ``<group>`` wrapper.

    Args:
        context (AnalysisContext): Analysis context holding the raw XML markup.
        config (XmlHierarchyConfig): Hierarchy thresholds and violation message templates.

    Returns:
        list[Violation]: A single violation when ungrouped repeated elements are found.
    """
    if tag_counts := re.findall(r"<([A-Za-z0-9_]+)>", context.code):
        duplicates = {
            tag
            for tag in tag_counts
            if tag_counts.count(tag) > MIN_TAG_OCCURRENCES_FOR_GROUP
        }
        if duplicates and "<group>" not in context.code:
            return [
                self.build_violation(
                    config,
                    contains=next(iter(duplicates)),
                    location=Location(line=1, column=1),
                    suggestion="Group repeated elements under a parent container.",
                ),
            ]
    return []

XmlClosingTagsDetector

XmlClosingTagsDetector()

Bases: ViolationDetector[XmlClosingTagsConfig], LocationHelperMixin

Identifies self-closing tags (<tag />) where explicit closing tags are preferred.

Self-closing syntax is valid XML, but in contexts where an element is expected to hold content (e.g., <description />) it can mask missing data. This detector flags self-closing elements so authors can verify that the empty content is intentional.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'xml-006' identifying the closing tags detector.

RETURNS DESCRIPTION
str

The 'xml-006' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Search for self-closing tag syntax (<tag />) in the XML document.

PARAMETER DESCRIPTION
context

Analysis context holding the raw XML markup.

TYPE: AnalysisContext

config

Closing tag thresholds and violation message templates.

TYPE: XmlClosingTagsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation when self-closing tags are found.

Source code in src/mcp_zen_of_languages/languages/xml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: XmlClosingTagsConfig,
) -> list[Violation]:
    """Search for self-closing tag syntax (``<tag />``) in the XML document.

    Args:
        context (AnalysisContext): Analysis context holding the raw XML markup.
        config (XmlClosingTagsConfig): Closing tag thresholds and violation message templates.

    Returns:
        list[Violation]: A single violation when self-closing tags are found.
    """
    if re.search(r"<([A-Za-z0-9_]+)\s*/>", context.code):
        return [
            self.build_violation(
                config,
                contains="self-closing",
                location=Location(line=1, column=1),
                suggestion="Use explicit closing tags when content is expected.",
            ),
        ]
    return []

YAML

mcp_zen_of_languages.languages.yaml.detectors

Detectors for YAML file quality, enforcing indentation, key conventions, and structural consistency.

Classes

YamlIndentationDetector

YamlIndentationDetector()

Bases: ViolationDetector[YamlIndentationConfig], LocationHelperMixin

Enforces uniform indentation width across all non-blank, non-comment lines.

YAML's block structure relies entirely on whitespace indentation, so inconsistent widths can silently change document semantics. This detector verifies that every indented line uses a multiple of the configured indent size (defaulting to two spaces) and flags deviations before they cause parsing surprises.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'yaml-001' identifying the indentation detector.

RETURNS DESCRIPTION
str

The 'yaml-001' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Check each non-blank line's leading spaces against the configured indent width.

PARAMETER DESCRIPTION
context

Analysis context holding the raw YAML text.

TYPE: AnalysisContext

config

Indentation thresholds including indent_size.

TYPE: YamlIndentationConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per line whose leading whitespace is not a multiple of indent_size.

Source code in src/mcp_zen_of_languages/languages/yaml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: YamlIndentationConfig,
) -> list[Violation]:
    """Check each non-blank line's leading spaces against the configured indent width.

    Args:
        context (AnalysisContext): Analysis context holding the raw YAML text.
        config (YamlIndentationConfig): Indentation thresholds including ``indent_size``.

    Returns:
        list[Violation]: One violation per line whose leading whitespace is not a multiple of *indent_size*.
    """
    violations: list[Violation] = []
    indent_size = config.indent_size
    for idx, line in enumerate(context.code.splitlines(), start=1):
        stripped = line.strip()
        if not stripped or stripped.startswith("#"):
            continue
        leading_spaces = len(line) - len(line.lstrip(" "))
        if "\t" in line[:leading_spaces]:
            continue
        if leading_spaces % indent_size != 0:
            violations.append(
                self.build_violation(
                    config,
                    contains="indentation",
                    location=Location(line=idx, column=1),
                    suggestion=f"Use {indent_size}-space indentation consistently.",
                ),
            )
    return violations

YamlNoTabsDetector

YamlNoTabsDetector()

Bases: ViolationDetector[YamlNoTabsConfig], LocationHelperMixin

Detects tab characters anywhere in YAML content.

The YAML specification explicitly prohibits tab characters for indentation; only spaces are allowed. Tabs embedded in values are technically legal but often indicate copy-paste errors. This detector flags every line containing a tab to prevent subtle parsing failures.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'yaml-002' identifying the no-tabs detector.

RETURNS DESCRIPTION
str

The 'yaml-002' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Scan every line for tab characters and report their positions.

PARAMETER DESCRIPTION
context

Analysis context holding the raw YAML text.

TYPE: AnalysisContext

config

No-tabs thresholds and violation message templates.

TYPE: YamlNoTabsConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per line containing a tab character.

Source code in src/mcp_zen_of_languages/languages/yaml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: YamlNoTabsConfig,
) -> list[Violation]:
    """Scan every line for tab characters and report their positions.

    Args:
        context (AnalysisContext): Analysis context holding the raw YAML text.
        config (YamlNoTabsConfig): No-tabs thresholds and violation message templates.

    Returns:
        list[Violation]: One violation per line containing a tab character.
    """
    violations: list[Violation] = [
        self.build_violation(
            config,
            contains="tabs",
            location=Location(line=idx, column=line.find("\t") + 1),
            suggestion="Replace tabs with spaces.",
        )
        for idx, line in enumerate(context.code.splitlines(), start=1)
        if "\t" in line
    ]
    return violations

YamlDuplicateKeysDetector

YamlDuplicateKeysDetector()

Bases: ViolationDetector[YamlDuplicateKeysConfig], LocationHelperMixin

Catches repeated top-level mapping keys that cause silent data loss.

YAML 1.1 allows duplicate keys with "last wins" semantics, while YAML 1.2 discourages them. Either way, duplicates usually indicate a merge conflict remnant or copy-paste mistake. This detector tracks seen top-level keys and flags any that appear more than once.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'yaml-003' identifying the duplicate keys detector.

RETURNS DESCRIPTION
str

The 'yaml-003' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Track top-level keys and flag any that appear more than once.

PARAMETER DESCRIPTION
context

Analysis context holding the raw YAML text.

TYPE: AnalysisContext

config

Duplicate key thresholds and violation message templates.

TYPE: YamlDuplicateKeysConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per duplicate key occurrence.

Source code in src/mcp_zen_of_languages/languages/yaml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: YamlDuplicateKeysConfig,
) -> list[Violation]:
    """Track top-level keys and flag any that appear more than once.

    Args:
        context (AnalysisContext): Analysis context holding the raw YAML text.
        config (YamlDuplicateKeysConfig): Duplicate key thresholds and violation message templates.

    Returns:
        list[Violation]: One violation per duplicate key occurrence.
    """
    violations: list[Violation] = []
    seen: set[str] = set()
    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.match(r"^([A-Za-z0-9_-]+)\s*:", line)
        if not match:
            continue
        key = match[1]
        if key in seen:
            violations.append(
                self.build_violation(
                    config,
                    contains=key,
                    location=Location(line=idx, column=1),
                    suggestion="Avoid duplicate keys in YAML mappings.",
                ),
            )
        seen.add(key)
    return violations

YamlLowercaseKeysDetector

YamlLowercaseKeysDetector()

Bases: ViolationDetector[YamlLowercaseKeysConfig], LocationHelperMixin

Enforces lowercase mapping keys throughout the YAML document.

YAML keys are case-sensitive, so Name and name are distinct. Mixing cases within a project causes confusion and breaks tools that rely on consistent key naming. This detector flags any key containing uppercase characters to encourage a uniform lowercase convention.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'yaml-004' identifying the lowercase keys detector.

RETURNS DESCRIPTION
str

The 'yaml-004' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Scan mapping keys and flag any containing uppercase characters.

PARAMETER DESCRIPTION
context

Analysis context holding the raw YAML text.

TYPE: AnalysisContext

config

Lowercase key thresholds and violation message templates.

TYPE: YamlLowercaseKeysConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: One violation per key with uppercase letters.

Source code in src/mcp_zen_of_languages/languages/yaml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: YamlLowercaseKeysConfig,
) -> list[Violation]:
    """Scan mapping keys and flag any containing uppercase characters.

    Args:
        context (AnalysisContext): Analysis context holding the raw YAML text.
        config (YamlLowercaseKeysConfig): Lowercase key thresholds and violation message templates.

    Returns:
        list[Violation]: One violation per key with uppercase letters.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.match(r"^\s*([A-Za-z0-9_-]+)\s*:", line)
        if not match:
            continue
        key = match[1]
        if any(char.isupper() for char in key):
            violations.append(
                self.build_violation(
                    config,
                    contains=key,
                    location=Location(line=idx, column=1),
                    suggestion="Use lowercase keys for consistency.",
                ),
            )
    return violations

YamlKeyClarityDetector

YamlKeyClarityDetector()

Bases: ViolationDetector[YamlKeyClarityConfig], LocationHelperMixin

Flags overly short mapping keys that sacrifice readability for brevity.

Single- or two-character keys like x or id are acceptable in some contexts but often indicate a missed opportunity for self-documenting names. This detector compares each key's length against a configurable minimum (default 3) and reports the first offender.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'yaml-005' identifying the key clarity detector.

RETURNS DESCRIPTION
str

The 'yaml-005' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Check each key's length and flag the first one shorter than min_key_length.

PARAMETER DESCRIPTION
context

Analysis context holding the raw YAML text.

TYPE: AnalysisContext

config

Key clarity thresholds including min_key_length.

TYPE: YamlKeyClarityConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation for the first overly short key found.

Source code in src/mcp_zen_of_languages/languages/yaml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: YamlKeyClarityConfig,
) -> list[Violation]:
    """Check each key's length and flag the first one shorter than *min_key_length*.

    Args:
        context (AnalysisContext): Analysis context holding the raw YAML text.
        config (YamlKeyClarityConfig): Key clarity thresholds including ``min_key_length``.

    Returns:
        list[Violation]: A single violation for the first overly short key found.
    """
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.match(r"^\s*([A-Za-z0-9_-]+)\s*:", line)
        if not match:
            continue
        key = match[1]
        if len(key) < config.min_key_length:
            violations.append(
                self.build_violation(
                    config,
                    contains=key,
                    location=Location(line=idx, column=1),
                    suggestion="Use more descriptive YAML keys.",
                ),
            )
            break
    return violations

YamlConsistencyDetector

YamlConsistencyDetector()

Bases: ViolationDetector[YamlConsistencyConfig], LocationHelperMixin

Ensures a single, consistent list-marker style is used throughout the document.

YAML allows - and * as sequence entry indicators, but mixing them in the same file confuses readers and may trip strict linters. This detector collects all markers used and flags the document when more than one style appears or when a disallowed marker is used.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'yaml-006' identifying the list-marker consistency detector.

RETURNS DESCRIPTION
str

The 'yaml-006' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Collect list markers (- vs *) and flag mixed or disallowed usage.

PARAMETER DESCRIPTION
context

Analysis context holding the raw YAML text.

TYPE: AnalysisContext

config

Consistency thresholds including allowed_list_markers.

TYPE: YamlConsistencyConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation when marker styles are inconsistent or disallowed.

Source code in src/mcp_zen_of_languages/languages/yaml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: YamlConsistencyConfig,
) -> list[Violation]:
    """Collect list markers (``-`` vs ``*``) and flag mixed or disallowed usage.

    Args:
        context (AnalysisContext): Analysis context holding the raw YAML text.
        config (YamlConsistencyConfig): Consistency thresholds including ``allowed_list_markers``.

    Returns:
        list[Violation]: A single violation when marker styles are inconsistent or disallowed.
    """
    markers: set[str] = set()
    for line in context.code.splitlines():
        stripped = line.lstrip()
        if stripped.startswith("- "):
            markers.add("-")
        elif stripped.startswith("* "):
            markers.add("*")
    if len(markers) > 1:
        return [
            self.build_violation(
                config,
                contains="list markers",
                location=Location(line=1, column=1),
                suggestion="Use a consistent list marker style (e.g., '-').",
            ),
        ]
    if (
        markers
        and config.allowed_list_markers
        and not markers.issubset(set(config.allowed_list_markers))
    ):
        return [
            self.build_violation(
                config,
                contains="list markers",
                location=Location(line=1, column=1),
                suggestion="Use allowed YAML list markers only.",
            ),
        ]
    return []

YamlCommentIntentDetector

YamlCommentIntentDetector()

Bases: ViolationDetector[YamlCommentIntentConfig], LocationHelperMixin

Ensures complex YAML files include explanatory comments.

Configuration files that exceed a minimum line count without any # comments are difficult for new contributors to understand. This detector counts non-empty content lines and comment lines, flagging documents that fall below the configured comment threshold relative to their size.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'yaml-007' identifying the comment intent detector.

RETURNS DESCRIPTION
str

The 'yaml-007' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Count non-empty and comment lines, flagging when comment coverage is too low.

PARAMETER DESCRIPTION
context

Analysis context holding the raw YAML text.

TYPE: AnalysisContext

config

Comment intent thresholds including min_comment_lines and min_nonempty_lines.

TYPE: YamlCommentIntentConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation when the file is large enough but lacks sufficient comments.

Source code in src/mcp_zen_of_languages/languages/yaml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: YamlCommentIntentConfig,
) -> list[Violation]:
    """Count non-empty and comment lines, flagging when comment coverage is too low.

    Args:
        context (AnalysisContext): Analysis context holding the raw YAML text.
        config (YamlCommentIntentConfig): Comment intent thresholds including ``min_comment_lines`` and ``min_nonempty_lines``.

    Returns:
        list[Violation]: A single violation when the file is large enough but lacks sufficient comments.
    """
    nonempty_lines = [
        line
        for line in context.code.splitlines()
        if line.strip() and not line.strip().startswith("---")
    ]
    comment_lines = [
        line for line in nonempty_lines if line.strip().startswith("#")
    ]
    if (
        len(nonempty_lines) >= config.min_nonempty_lines
        and len(comment_lines) < config.min_comment_lines
    ):
        return [
            self.build_violation(
                config,
                contains="comment",
                location=Location(line=1, column=1),
                suggestion="Add comments to explain intent in complex YAML.",
            ),
        ]
    return []

YamlStringStyleDetector

YamlStringStyleDetector()

Bases: ViolationDetector[YamlStringStyleConfig], LocationHelperMixin

Flags unquoted string values that contain spaces or special YAML characters.

Unquoted strings with colons, hashes, or spaces can be misinterpreted by parsers—for example, key: value: extra may be parsed differently than intended. This detector identifies such values and recommends wrapping them in single or double quotes to eliminate ambiguity.

Note

Boolean literals (true, false, null) and plain numbers are excluded from this check.

Source code in src/mcp_zen_of_languages/analyzers/base.py
def __init__(self) -> None:
    """Initialize the detector with an empty rule-ID list.

    Concrete rule IDs are injected later by the pipeline builder in
    [`BaseAnalyzer.build_pipeline`][mcp_zen_of_languages.analyzers.base.BaseAnalyzer.build_pipeline]
    after matching this detector to its zen-rule definitions.
    """
    self.rule_ids = []
Attributes
name property
name

Return 'yaml-008' identifying the string style detector.

RETURNS DESCRIPTION
str

The 'yaml-008' rule identifier.

TYPE: str

Functions
detect
detect(context, config)

Search for unquoted values containing spaces, colons, or hashes that need quoting.

PARAMETER DESCRIPTION
context

Analysis context holding the raw YAML text.

TYPE: AnalysisContext

config

String style thresholds including require_quotes_for_specials.

TYPE: YamlStringStyleConfig

RETURNS DESCRIPTION
list[Violation]

list[Violation]: A single violation for the first unquoted special-character value found.

Source code in src/mcp_zen_of_languages/languages/yaml/detectors.py
def detect(
    self,
    context: AnalysisContext,
    config: YamlStringStyleConfig,
) -> list[Violation]:
    """Search for unquoted values containing spaces, colons, or hashes that need quoting.

    Args:
        context (AnalysisContext): Analysis context holding the raw YAML text.
        config (YamlStringStyleConfig): String style thresholds including ``require_quotes_for_specials``.

    Returns:
        list[Violation]: A single violation for the first unquoted special-character value found.
    """
    if not config.require_quotes_for_specials:
        return []
    violations: list[Violation] = []
    for idx, line in enumerate(context.code.splitlines(), start=1):
        match = re.match(r"^\s*([A-Za-z0-9_-]+)\s*:\s*(.+)$", line)
        if not match:
            continue
        value = match[2].strip()
        if not value or value.startswith(("#", "|", ">")):
            continue
        if value[0] in {"'", '"'}:
            continue
        if re.fullmatch(r"(true|false|null)", value):
            continue
        if re.fullmatch(r"[0-9]+(\.[0-9]+)?", value):
            continue
        if re.search(r"[\s:#]", value):
            violations.append(
                self.build_violation(
                    config,
                    contains=value,
                    location=Location(line=idx, column=1),
                    suggestion="Quote strings containing spaces or special characters.",
                ),
            )
            break
    return violations