suite check: реализована проверка целостности набора
- разбор документа по языку конвенций: шапка, области правил, блоки под метками - проверки формы правила, распространения, ссылок и самого suite.toml - словарь языка живёт в бинаре реестром «версия × естественный язык», темы и префиксы берутся только из манифеста
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package doc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Front — шапка файла. Ключей немного и все они плоские, поэтому разбор здесь
|
||||
// свой: тащить YAML ради четырёх строк `ключ: значение` не за что.
|
||||
//
|
||||
// Ось слоя объявляется здесь ключами lang и stack, а не выводится из пути
|
||||
// (META-38); отсутствие обоих означает базовый слой темы.
|
||||
type Front struct {
|
||||
Topic string
|
||||
Prefix string
|
||||
Lang string
|
||||
Stack string
|
||||
Extends string
|
||||
|
||||
// At — номер строки, на которой объявлен ключ; нужен, чтобы находка
|
||||
// показывала на объявление, а не на начало файла.
|
||||
At map[string]int
|
||||
// Unknown — ключи, которых модель не знает.
|
||||
Unknown []string
|
||||
// End — номер строки закрывающего разделителя. Тело файла начинается
|
||||
// со следующей.
|
||||
End int
|
||||
// Present — была ли шапка вообще.
|
||||
Present bool
|
||||
}
|
||||
|
||||
// Axis отвечает, объявлена ли у слоя ось. Слой без ключей оси — базовый.
|
||||
func (f Front) Axis() bool {
|
||||
return f.Lang != "" || f.Stack != ""
|
||||
}
|
||||
|
||||
// parseFront разбирает шапку из строк файла. Возвращает шапку и номер первой
|
||||
// строки тела.
|
||||
func parseFront(lines []string) (Front, int, error) {
|
||||
front := Front{At: make(map[string]int)}
|
||||
if len(lines) == 0 || strings.TrimSpace(lines[0]) != "---" {
|
||||
return front, 1, nil
|
||||
}
|
||||
front.Present = true
|
||||
|
||||
for i := 1; i < len(lines); i++ {
|
||||
line := lines[i]
|
||||
num := i + 1
|
||||
if strings.TrimSpace(line) == "---" {
|
||||
front.End = num
|
||||
return front, num + 1, nil
|
||||
}
|
||||
if strings.TrimSpace(line) == "" {
|
||||
continue
|
||||
}
|
||||
key, value, ok := strings.Cut(line, ":")
|
||||
if !ok {
|
||||
return front, num, fmt.Errorf("строка %d шапки не имеет вида «ключ: значение»", num)
|
||||
}
|
||||
key = strings.TrimSpace(key)
|
||||
value = strings.TrimSpace(value)
|
||||
front.At[key] = num
|
||||
|
||||
switch key {
|
||||
case "topic":
|
||||
front.Topic = value
|
||||
case "prefix":
|
||||
front.Prefix = value
|
||||
case "lang":
|
||||
front.Lang = value
|
||||
case "stack":
|
||||
front.Stack = value
|
||||
case "extends":
|
||||
front.Extends = value
|
||||
default:
|
||||
front.Unknown = append(front.Unknown, key)
|
||||
}
|
||||
}
|
||||
return front, len(lines) + 1, fmt.Errorf("шапка не закрыта разделителем ---")
|
||||
}
|
||||
Reference in New Issue
Block a user