This commit is contained in:
retoor 2026-07-08 12:10:42 +02:00
parent 3dacbb3ab0
commit 608974021d
7 changed files with 44 additions and 44 deletions

22
.gitignore vendored
View File

@ -4,7 +4,7 @@ tests/test_json_exhaustive
tests/test_toml_exhaustive
tests/test_yaml_exhaustive
*.bak*
# ── Nim ──────────────────────────────────────────────────────────────────
# -- Nim ------------------------------------------------------------------
nimcache/
nimblecache/
*.exe
@ -15,10 +15,10 @@ nimblecache/
*.so
*.dylib
# ── Binaries (compiled output) ───────────────────────────────────────────
# -- Binaries (compiled output) -------------------------------------------
bin/
# ── Test compiled binaries (source is .nim, binaries have no extension) ──
# -- Test compiled binaries (source is .nim, binaries have no extension) --
tests/test_all
tests/test_bash
tests/test_nim
@ -35,16 +35,16 @@ tests/test_mixed
tests/test_config
tests/test_fuzz
# ── Logs ─────────────────────────────────────────────────────────────────
# -- Logs -----------------------------------------------------------------
*.log
# ── Python cache ─────────────────────────────────────────────────────────
# -- Python cache ---------------------------------------------------------
__pycache__/
*.pyc
*.pyo
*.pyd
# ── OS files ─────────────────────────────────────────────────────────────
# -- OS files -------------------------------------------------------------
.DS_Store
.DS_Store?
._*
@ -54,7 +54,7 @@ ehthumbs.db
Thumbs.db
desktop.ini
# ── Editor files ─────────────────────────────────────────────────────────
# -- Editor files ---------------------------------------------------------
*.swp
*.swo
*~
@ -65,23 +65,23 @@ desktop.ini
*.sublime-project
*.sublime-workspace
# ── Environment / secrets ────────────────────────────────────────────────
# -- Environment / secrets ------------------------------------------------
.env
.env.local
.env.*.local
*.env
!.env.example
# ── Temporary / backup files ─────────────────────────────────────────────
# -- Temporary / backup files ---------------------------------------------
/tmp/
*.tmp
*.temp
*.pid
# ── dpc agent logs ───────────────────────────────────────────────────────
# -- dpc agent logs -------------------------------------------------------
dpc.log
# ── Coverage reports ─────────────────────────────────────────────────────
# -- Coverage reports -----------------------------------------------------
*.gcda
*.gcno
*.gcov

View File

@ -88,8 +88,8 @@ Each validator:
1. Creates its tokenizer and runs `tokenize()`
2. Collects tokenizer errors
3. Runs `analyzeTokens()` language-specific structural analysis
4. Runs `buildModuleInfo()` populates `ModuleInfo` with imports, functions, classes
3. Runs `analyzeTokens()` - language-specific structural analysis
4. Runs `buildModuleInfo()` - populates `ModuleInfo` with imports, functions, classes
5. Computes validity, warning/info counts, duration
Validators register themselves via a factory pattern at import time. The registry maps flavor strings (e.g., `"python"`, `"bash"`) to constructors.
@ -674,7 +674,7 @@ Every validation function follows the same contract:
| `sourcePath: string = ""` (optional) | `ValidationResult.durationMs: float` |
**Guarantees**:
- Never throws all exceptions are caught and returned as `E9999` errors
- Never throws - all exceptions are caught and returned as `E9999` errors
- Empty source returns `E0009` (or `valid: true` for YAML/TOML where empty is valid)
- File not found returns `E0011`
- Unknown flavor with no detection possible returns an `E0007` error
@ -686,8 +686,8 @@ Every validation function follows the same contract:
| Aspect | Details |
|--------|---------|
| Tokenizer | `nim_tokenizer.nim` `NimTokenizer` |
| Validator | `nim_validator.nim` `NimValidator` |
| Tokenizer | `nim_tokenizer.nim` - `NimTokenizer` |
| Validator | `nim_validator.nim` - `NimValidator` |
| Keywords | 80+ (addr, and, as, block, break, case, const, converter, defer, discard, elif, else, enum, except, export, finally, for, from, func, if, import, in, include, iterator, let, macro, method, mixin, mod, nil, not, object, of, or, proc, ptr, raise, ref, return, template, try, tuple, type, using, var, when, while, with, yield, etc.) |
| Error Code | Condition | Severity | Hint |
@ -707,8 +707,8 @@ Structural extraction: imports (`from X import Y`), functions (`proc`, `func`, `
| Aspect | Details |
|--------|---------|
| Tokenizer | `bash_tokenizer.nim` `BashTokenizer` |
| Validator | `bash_validator.nim` `BashValidator` |
| Tokenizer | `bash_tokenizer.nim` - `BashTokenizer` |
| Validator | `bash_validator.nim` - `BashValidator` |
| Keywords | 38+ (if, then, else, elif, fi, case, esac, for, while, until, do, done, in, function, select, time, return, break, continue, exit, declare, local, export, readonly, unset, eval, exec, let, source, shift, trap, type, typeset, ulimit, umask, alias, read, echo) |
| Error Code | Condition | Severity | Hint |
@ -728,8 +728,8 @@ Special features: shebang detection (`#!`), heredoc detection (`<<EOF`), variabl
| Aspect | Details |
|--------|---------|
| Tokenizer | `python_tokenizer.nim` `PythonTokenizer` |
| Validator | `python_validator.nim` `PythonValidator` |
| Tokenizer | `python_tokenizer.nim` - `PythonTokenizer` |
| Validator | `python_validator.nim` - `PythonValidator` |
| Keywords | 33 (False, None, True, and, as, assert, async, await, break, class, continue, def, del, elif, else, except, finally, for, from, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, return, try, while, with, yield) |
| Error Code | Condition | Severity | Hint |
@ -749,8 +749,8 @@ Structural extraction: imports (`import X`, `from X import Y`), functions (`def`
| Aspect | Details |
|--------|---------|
| Tokenizer | `javascript_tokenizer.nim` `JavaScriptTokenizer` |
| Validator | `javascript_validator.nim` `JavaScriptValidator` |
| Tokenizer | `javascript_tokenizer.nim` - `JavaScriptTokenizer` |
| Validator | `javascript_validator.nim` - `JavaScriptValidator` |
| Keywords | 60+ (async, await, break, case, catch, class, const, continue, debugger, default, delete, do, else, export, extends, false, finally, for, function, if, import, in, instanceof, let, new, null, of, return, super, switch, static, this, throw, true, try, typeof, var, void, while, with, yield + TypeScript: interface, type, declare, module, namespace, abstract, readonly, as, any, boolean, number, string, never, keyof, infer, unknown) |
| Error Code | Condition | Severity | Hint |
@ -768,9 +768,9 @@ Structural extraction: imports/exports, functions (`function`, `async`), classes
| Aspect | Details |
|--------|---------|
| Tokenizer | `php_tokenizer.nim` `PHPTokenizer` |
| Validator | `php_validator.nim` `PHPValidator` |
| Mode switching | Tracks `inPhpMode` flag toggles on `<?php`/`<?` and `?>` |
| Tokenizer | `php_tokenizer.nim` - `PHPTokenizer` |
| Validator | `php_validator.nim` - `PHPValidator` |
| Mode switching | Tracks `inPhpMode` flag - toggles on `<?php`/`<?` and `?>` |
| Error Code | Condition | Severity | Hint |
|------------|-----------|----------|------|
@ -785,8 +785,8 @@ Structural extraction: functions (`function`, `fn`), classes (`class`), imports/
| Aspect | Details |
|--------|---------|
| Tokenizer | `html_tokenizer.nim` `HTMLTokenizer` |
| Validator | `html_validator.nim` `HTMLValidator` |
| Tokenizer | `html_tokenizer.nim` - `HTMLTokenizer` |
| Validator | `html_validator.nim` - `HTMLValidator` |
| Void elements | 14: area, base, br, col, embed, hr, img, input, link, meta, param, source, track, wbr |
| Error Code | Condition | Severity | Hint |
@ -801,8 +801,8 @@ Special features: tag stack balancing, void element awareness (no closing tag ne
| Aspect | Details |
|--------|---------|
| Tokenizer | `jinja_tokenizer.nim` `JinjaTokenizer` |
| Validator | `jinja_validator.nim` `JinjaValidator` |
| Tokenizer | `jinja_tokenizer.nim` - `JinjaTokenizer` |
| Validator | `jinja_validator.nim` - `JinjaValidator` |
| Error Code | Condition | Severity | Hint |
|------------|-----------|----------|------|
@ -820,7 +820,7 @@ Special features: tracks 12 block tag types (`for`, `if`, `block`, `macro`, `fil
| Aspect | Details |
|--------|---------|
| Validator | `config_validators.nim` `JSONValidator` |
| Validator | `config_validators.nim` - `JSONValidator` |
| Method | Uses Nim's built-in `parseJson()` for full validation |
| Error Code | Condition | Severity | Hint |
@ -833,7 +833,7 @@ Special features: tracks 12 block tag types (`for`, `if`, `block`, `macro`, `fil
| Aspect | Details |
|--------|---------|
| Validator | `config_validators.nim` `YAMLValidator` |
| Validator | `config_validators.nim` - `YAMLValidator` |
| Method | Line-by-line structural analysis |
| Error Code | Condition | Severity | Hint |
@ -849,7 +849,7 @@ Note: Empty YAML (only whitespace/comments) is `valid: true`.
| Aspect | Details |
|--------|---------|
| Validator | `config_validators.nim` `TOMLValidator` |
| Validator | `config_validators.nim` - `TOMLValidator` |
| Method | Line-by-line structural analysis |
| Error Code | Condition | Severity | Hint |
@ -912,7 +912,7 @@ Supported flavors:
| 0 | Validation successful (or help/version requested) |
| Non-zero (Nim default) | Runtime error |
Note: The `validate` command always exits 0 on the Nim level; the `valid` field in the output indicates pass/fail. This is by design Nimcheck never crashes.
Note: The `validate` command always exits 0 on the Nim level; the `valid` field in the output indicates pass/fail. This is by design - Nimcheck never crashes.
---
@ -1084,7 +1084,7 @@ See `LESSONS_LEARNED.md` for the complete checklist (Section 14). The minimum st
### Design Principles
- **KISS**: Keep validators simple tokenize, analyze brackets, report
- **KISS**: Keep validators simple - tokenize, analyze brackets, report
- **Never crash**: Every validation path in a try/except
- **No external deps**: Pure Nim standard library
- **DRY**: Common logic in `tokenizerbase.nim` and `validatorbase.nim`

View File

@ -17,7 +17,7 @@
import std/[json, strutils, os, strformat, sequtils, algorithm]
# Core types and base classes imported and re-exported for public API consumers
# Core types and base classes - imported and re-exported for public API consumers
import nimcheck/core/types
import nimcheck/core/tokenizerbase
import nimcheck/core/validatorbase

View File

@ -1,4 +1,4 @@
## Validator registration called at module load time.
## Validator registration - called at module load time.
##
## Each language validator registers itself here.
## This file is imported by the main nimcheck.nim module.

View File

@ -202,7 +202,7 @@ proc validateBrackets*(self: TokenizerBase): seq[ValidationError] =
let hintStr = &"Add a closing '{pairStr}' before this point"
let err = newValidationError(
esError,
&"Unclosed '{ch}' expected matching '{pairStr}'",
&"Unclosed '{ch}' - expected matching '{pairStr}'",
ErrUnclosedBracket,
pos,
SourceRange(startPos: pos, endPos: pos),
@ -215,12 +215,12 @@ proc validateBrackets*(self: TokenizerBase): seq[ValidationError] =
self.errors.add(result)
# ---------------------------------------------------------------------------
# Abstract interface subclasses must implement
# Abstract interface - subclasses must implement
# ---------------------------------------------------------------------------
method tokenize*(self: TokenizerBase) {.base, gcsafe.} =
## Tokenize the entire source. Must be overridden.
raise newException(ValueError, "tokenize() not implemented subclass must override")
raise newException(ValueError, "tokenize() not implemented - subclass must override")
proc getAllTokens*(self: TokenizerBase): seq[Token] =
## Get all tokens after tokenization.

View File

@ -36,7 +36,7 @@ proc newValidatorBase*(
result.result.flavor = options.flavor
# ---------------------------------------------------------------------------
# Template methods subclasses override
# Template methods - subclasses override
# ---------------------------------------------------------------------------
method createTokenizer*(self: ValidatorBase): TokenizerBase {.base, gcsafe.} =
@ -121,7 +121,7 @@ method validate*(self: ValidatorBase): ValidationResult {.base, gcsafe.} =
self.result.moduleInfo.linesOfCode = self.source.count('\n') + 1
except Exception as e:
# Never crash always report useful error
# Never crash - always report useful error
self.result.valid = false
self.result.errors.add(newValidationError(
esCritical,
@ -129,7 +129,7 @@ method validate*(self: ValidatorBase): ValidationResult {.base, gcsafe.} =
"E9999",
newSourcePosition(0, 0, 0),
newSourceRange(newSourcePosition(0, 0, 0), newSourcePosition(0, 0, 0)),
hint = "This is a bug in the validator please report it"
hint = "This is a bug in the validator - please report it"
))
when defined(nimcheckDebug):
if self.options.debugMode:
@ -162,7 +162,7 @@ proc isValid*(self: ValidatorBase): bool =
self.result.valid
# ---------------------------------------------------------------------------
# Factory create correct validator for a flavor
# Factory - create correct validator for a flavor
# ---------------------------------------------------------------------------
type

View File

@ -77,7 +77,7 @@ method tokenize*(self: PHPTokenizer) =
self.emitToken(tkNewline, "\n", startPos)
continue
# Inside PHP mode check for exit
# Inside PHP mode - check for exit
if self.peekString(2) == "?>" and self.inPhpMode:
for _ in 1..2: discard self.advance()
self.emitToken(tkDirective, "?>", startPos)