suite check: реализована проверка целостности набора
- разбор документа по языку конвенций: шапка, области правил, блоки под метками - проверки формы правила, распространения, ссылок и самого suite.toml - словарь языка живёт в бинаре реестром «версия × естественный язык», темы и префиксы берутся только из манифеста
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
package check
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"git.vakhrushev.me/av/convy/internal/manifest"
|
||||
"git.vakhrushev.me/av/convy/internal/suite"
|
||||
)
|
||||
|
||||
// Suite прогоняет все проверки набора и возвращает отчёт.
|
||||
func Suite(s *suite.Suite) *Report {
|
||||
rep := &Report{}
|
||||
checkManifest(s, rep)
|
||||
checkBaseLayers(s, rep)
|
||||
|
||||
for _, d := range s.Docs {
|
||||
checkForm(s, d, rep)
|
||||
checkLinks(s, d, rep)
|
||||
if d.Front.Topic != "" {
|
||||
checkSpread(s, d, rep)
|
||||
}
|
||||
}
|
||||
return rep
|
||||
}
|
||||
|
||||
// checkManifest проверяет сам манифест: форму префиксов, непересечение живого
|
||||
// с выбывшим, наличие объявленных файлов и отсутствие незарегистрированных.
|
||||
func checkManifest(s *suite.Suite, rep *Report) {
|
||||
m := s.Manifest
|
||||
|
||||
for _, key := range m.Undecoded {
|
||||
rep.Warnf(Manifest, manifest.Name, 0, "ключ %s инструменту неизвестен", key)
|
||||
}
|
||||
for _, name := range []string{m.Language.Description, m.Language.Reading} {
|
||||
if name != "" && !s.Exists(name) {
|
||||
rep.Errorf(Manifest, manifest.Name, 0, "секция [language] объявляет документ %q, а файла нет", name)
|
||||
}
|
||||
}
|
||||
|
||||
byPath := make(map[string][]string)
|
||||
for _, prefix := range m.LivePrefixes() {
|
||||
if err := manifest.ValidPrefix(prefix); err != nil {
|
||||
rep.Errorf(Manifest, manifest.Name, 0, "%s", err)
|
||||
}
|
||||
if m.PrefixRetired(prefix) {
|
||||
rep.Errorf(Manifest, manifest.Name, 0,
|
||||
"префикс %s значится и среди живых, и среди выбывших: выбывший не выдаётся повторно", prefix)
|
||||
}
|
||||
path := m.Prefixes.Live[prefix]
|
||||
byPath[path] = append(byPath[path], prefix)
|
||||
}
|
||||
for _, path := range sortedKeys(byPath) {
|
||||
if prefixes := byPath[path]; len(prefixes) > 1 {
|
||||
sort.Strings(prefixes)
|
||||
rep.Errorf(Manifest, manifest.Name, 0,
|
||||
"на файл %q объявлено несколько префиксов (%v): префикс принадлежит файлу", path, prefixes)
|
||||
}
|
||||
}
|
||||
for prefix := range m.Prefixes.Retired {
|
||||
if err := manifest.ValidPrefix(prefix); err != nil {
|
||||
rep.Errorf(Manifest, manifest.Name, 0, "среди выбывших: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, prefix := range sortedKeys(s.Missing) {
|
||||
rep.Errorf(Manifest, manifest.Name, 0,
|
||||
"префикс %s объявлен за файлом %q, а файла в наборе нет", prefix, s.Missing[prefix])
|
||||
}
|
||||
for _, path := range s.Unregistered {
|
||||
rep.Errorf(Manifest, path, 1,
|
||||
"файл записан языком конвенций, но в манифесте набора не объявлен: для набора его нет")
|
||||
}
|
||||
for _, err := range s.Broken {
|
||||
rep.Errorf(Manifest, manifest.Name, 0, "%s", err)
|
||||
}
|
||||
|
||||
for _, topic := range m.LiveTopics() {
|
||||
if m.TopicRetired(topic) {
|
||||
rep.Errorf(Manifest, manifest.Name, 0,
|
||||
"тема %q значится и среди живых, и среди выбывших", topic)
|
||||
}
|
||||
if len(s.Layers(topic)) == 0 {
|
||||
rep.Errorf(Manifest, manifest.Name, 0,
|
||||
"тема %q объявлена живой, а слоёв у неё в наборе нет: тема живёт, пока есть хотя бы один слой", topic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkBaseLayers проверяет, что у темы не больше одного слоя без ключей оси.
|
||||
// Базовый слой единственный: он попадает в копию всегда, и второй такой
|
||||
// означал бы два базовых текста в одном собранном файле.
|
||||
func checkBaseLayers(s *suite.Suite, rep *Report) {
|
||||
for _, topic := range s.Manifest.LiveTopics() {
|
||||
var base []string
|
||||
for _, d := range s.Layers(topic) {
|
||||
if !d.Front.Axis() {
|
||||
base = append(base, d.Path)
|
||||
}
|
||||
}
|
||||
if len(base) > 1 {
|
||||
sort.Strings(base)
|
||||
for _, path := range base[1:] {
|
||||
rep.Errorf(Spread, path, 1,
|
||||
"у темы %q больше одного слоя без ключей оси: базовый слой единственный, остальные — %v",
|
||||
topic, base)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sortedKeys[V any](m map[string]V) []string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
Reference in New Issue
Block a user