Files
convy/internal/check/report.go
T
av ccf046fb7b suite check: реализована проверка целостности набора
- разбор документа по языку конвенций: шапка, области правил, блоки под метками
- проверки формы правила, распространения, ссылок и самого suite.toml
- словарь языка живёт в бинаре реестром «версия × естественный язык», темы и
  префиксы берутся только из манифеста
2026-07-27 09:53:07 +03:00

107 lines
3.6 KiB
Go

// Package check прогоняет проверки целостности набора.
//
// Деление на семейства взято из языка и сохранено в коде: форма правила
// проверяется в любом файле, который язык употребляет; распространение — только
// в файлах конвенций, потому что эти проверки о том, что документ уезжает к
// потребителю. Третья часть списка — взаимоисключительность строк таблицы,
// покрытие области действия, самодостаточность нормы — сюда не входит: она не
// даётся разбором текста и остаётся работой читателя.
package check
import (
"fmt"
"sort"
)
// Severity различает ошибку и предупреждение. Ошибка — нарушение, названное
// правилом набора; предупреждение — то, что стоит посмотреть глазами.
type Severity int
const (
Error Severity = iota + 1
Warning
)
func (s Severity) String() string {
if s == Warning {
return "предупреждение"
}
return "ошибка"
}
// Family — семейство проверок, из которого пришла находка.
type Family string
const (
Manifest Family = "манифест"
Form Family = "форма"
Spread Family = "распространение"
Links Family = "ссылки"
)
// Finding — одна находка.
type Finding struct {
Severity Severity
Family Family
// Path — путь файла от корня набора; пусто, если находка о наборе целиком.
Path string
// Line — строка файла; ноль, если находка не привязана к строке.
Line int
Msg string
}
// Report накапливает находки одного прогона.
type Report struct {
findings []Finding
}
// Errorf записывает ошибку.
func (r *Report) Errorf(f Family, path string, line int, format string, args ...any) {
r.add(Error, f, path, line, format, args...)
}
// Warnf записывает предупреждение.
func (r *Report) Warnf(f Family, path string, line int, format string, args ...any) {
r.add(Warning, f, path, line, format, args...)
}
func (r *Report) add(s Severity, f Family, path string, line int, format string, args ...any) {
r.findings = append(r.findings, Finding{
Severity: s,
Family: f,
Path: path,
Line: line,
Msg: fmt.Sprintf(format, args...),
})
}
// Findings отдаёт находки в порядке файла и строки. Находки о наборе целиком
// идут первыми: пока манифест не сходится, остальное читать рано.
func (r *Report) Findings() []Finding {
out := make([]Finding, len(r.findings))
copy(out, r.findings)
sort.SliceStable(out, func(i, j int) bool {
if out[i].Path != out[j].Path {
return out[i].Path < out[j].Path
}
return out[i].Line < out[j].Line
})
return out
}
// Errors считает находки уровня ошибки.
func (r *Report) Errors() int {
n := 0
for _, f := range r.findings {
if f.Severity == Error {
n++
}
}
return n
}
// Warnings считает предупреждения.
func (r *Report) Warnings() int {
return len(r.findings) - r.Errors()
}