Skip to content

Latest commit

 

History

History
73 lines (51 loc) · 4.1 KB

File metadata and controls

73 lines (51 loc) · 4.1 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

This repository is the JSF-Lint tool itself: a configurable Python-based C++ linter built on simplified JSF AV C++ Coding Standards. Two core files:

  • jsf_lint.py — the linter engine (all rule checkers, CLI, output formatters)
  • linter_rules.yaml — rule configuration (categories, enable/disable, severity, thresholds, patterns)

Note: claude-code/ contains a distributable CLAUDE.md and /lint slash command intended to be copied into downstream C++ projects that adopt these standards. It is not the CLAUDE.md for this repository.

Commands

# Run the linter
python jsf_lint.py <file_or_directory>
python jsf_lint.py <target> --format json           # JSON output for tooling
python jsf_lint.py <target> --format github         # GitHub Actions annotations
python jsf_lint.py <target> --config custom.yaml    # Non-default config
python jsf_lint.py <target> --error-exit            # Exit 1 if any errors found

# Run tests (from repo root)
python -m pytest tests/test_checkers.py -v
python tests/test_checkers.py                       # Without pytest

# Install dependencies
pip install pyyaml
pip install pytest   # for tests

Architecture

Engine (jsf_lint.py)

All rule checkers inherit from RuleChecker (base class holding rule_id, severity, jsf_ref, params; check() returns list[Violation]):

  • PatternChecker — handles all regex-based rules via pattern: or patterns: from YAML. Most prohibited-feature rules use this.
  • Custom subclasses for rules requiring more logic: MaxFunctionLengthChecker, MaxFunctionArgsChecker, MaxLineLengthChecker, NoTabsChecker, IncludeGuardChecker, BracesRequiredChecker, SwitchDefaultChecker, CStyleCommentChecker, MagicNumberChecker, NoCStyleCastChecker, DefineOnlyForGuardsChecker.

JSFLinter is the main engine:

  • Loads linter_rules.yaml, builds enabled RuleChecker instances via CHECKER_MAP (maps YAML rule key → checker class).
  • lint_file(): reads a file, strips comments (strip_comments()), runs all checkers, applies inline NOLINT suppressions.
  • lint_path(): walks files/directories, aggregates LintResult.

Key utilities (used to avoid false positives):

  • strip_string_literals(line) — replaces string/char literal content with _ before pattern matching.
  • strip_comments(lines) — replaces comment text with spaces, preserving line/column positions.
  • has_nolint(line, rule_id, marker) — checks for // NOLINT(rule_name) inline suppression.

Configuration (linter_rules.yaml)

Rules are grouped into categories: complexity, prohibited_features, type_safety, memory_safety, control_flow, style, classes, embedded. Each rule key must have a matching entry in JSFLinter.CHECKER_MAP.

  • Pattern-based rules only need a pattern: or patterns: field — no Python code required.
  • Custom-logic rules require a RuleChecker subclass registered in CHECKER_MAP.
  • Config is auto-detected by searching upward from CWD for linter_rules.yaml or .jsflint.yaml.
  • The suppressions section configures inline_marker (default: NOLINT) and excluded_paths.

Tests (tests/)

test_checkers.py runs the linter as a subprocess and parses JSON output. Three C++ fixtures in tests/fixtures/:

  • all_errors.cpp — one instance of every violation (rule coverage)
  • clean.cpp — violation-free; must always produce zero violations
  • suppressions.cpp — verifies // NOLINT(rule_id) suppresses correctly

Adding a New Rule

  1. Add the rule entry under the appropriate category in linter_rules.yaml.
  2. If regex-based, add pattern: or patterns:PatternChecker handles it automatically with no Python changes.
  3. If custom logic is needed, create a RuleChecker subclass in jsf_lint.py and register it in JSFLinter.CHECKER_MAP.
  4. Add a violation example to tests/fixtures/all_errors.cpp and a clean counterpart to tests/fixtures/clean.cpp, then add assertions in test_checkers.py.