комментарии и сообщения переведены на английский
- комментарии, тексты ошибок, вывод CLI и сообщения тестов теперь на английском - по-русски остались только литералы словаря ru и содержимое фикстур: это данные под проверкой, а не текст инструмента - согласование числительных в итоге упростилось до английского plural
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
// Package manifest читает suite.toml — манифест набора конвенций.
|
||||
// Package manifest reads suite.toml, the manifest of a conventions suite.
|
||||
//
|
||||
// Манифест объявляет три вещи: язык, которым записаны правила набора, живые и
|
||||
// выбывшие темы, живые и выбывшие префиксы правил вместе с путями к файлам.
|
||||
// Инструмент не знает ни одной темы и ни одного префикса заранее — весь этот
|
||||
// список приходит отсюда.
|
||||
// The manifest declares three things: the language the suite's rules are
|
||||
// written in, its live and retired topics, and its live and retired rule
|
||||
// prefixes together with the paths of their files. The tool knows no topic and
|
||||
// no prefix in advance — that whole list arrives from here.
|
||||
package manifest
|
||||
|
||||
import (
|
||||
@@ -17,17 +17,19 @@ import (
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
// Name — имя манифеста набора. По тому, какой из двух манифестов лежит рядом,
|
||||
// определяется контекст: suite.toml — набор, .conventions.toml — проект.
|
||||
// Name is the name of a suite manifest. Which of the two manifests lies next
|
||||
// to you tells you where you are: suite.toml means a suite, .conventions.toml
|
||||
// means a project.
|
||||
const Name = "suite.toml"
|
||||
|
||||
// DefaultLanguageCode — естественный язык набора, когда манифест о нём молчит.
|
||||
// Ключ необязателен намеренно: словарь живёт в бинаре, и заставлять каждый
|
||||
// набор объявлять то, что и так подразумевается, незачем.
|
||||
// DefaultLanguageCode is the suite's natural language when the manifest says
|
||||
// nothing about it. The key is optional on purpose: the vocabulary lives in the
|
||||
// binary, and making every suite declare what is already implied buys nothing.
|
||||
const DefaultLanguageCode = "ru"
|
||||
|
||||
// Language — секция [language]: версия языка конвенций и два документа о нём.
|
||||
// Полное описание остаётся у автора набора, короткое едет в копию.
|
||||
// Language is the [language] section: the version of the conventions language
|
||||
// and the two documents about it. The full description stays with the author of
|
||||
// the suite, the short one travels into the copy.
|
||||
type Language struct {
|
||||
Version int `toml:"version"`
|
||||
Lang string `toml:"lang"`
|
||||
@@ -35,39 +37,40 @@ type Language struct {
|
||||
Reading string `toml:"reading"`
|
||||
}
|
||||
|
||||
// Section — раздел манифеста, разбитый на живую и выбывшую части. Выбывшее
|
||||
// хранится, а не удаляется: имя темы и префикс правила живут в чужих
|
||||
// репозиториях, и переиспользовать их нельзя никогда.
|
||||
// Section is a part of the manifest split into a live and a retired half.
|
||||
// Retired entries are kept rather than deleted: a topic name and a rule prefix
|
||||
// live on in foreign repositories, and neither may ever be reused.
|
||||
type Section struct {
|
||||
Live map[string]string `toml:"live"`
|
||||
Retired map[string]string `toml:"retired"`
|
||||
}
|
||||
|
||||
// Manifest — разобранный suite.toml.
|
||||
// Manifest is a parsed suite.toml.
|
||||
type Manifest struct {
|
||||
Language Language `toml:"language"`
|
||||
Topics Section `toml:"topics"`
|
||||
Prefixes Section `toml:"prefixes"`
|
||||
|
||||
// Path — путь, по которому манифест прочитан.
|
||||
// Path is where the manifest was read from.
|
||||
Path string `toml:"-"`
|
||||
// Undecoded — ключи, которых инструмент не знает. Опечатка в манифесте
|
||||
// иначе прошла бы молча, а стоит она подписки или целого файла.
|
||||
// Undecoded lists keys the tool does not know. A typo in the manifest
|
||||
// would otherwise pass in silence, and it costs a subscription or a
|
||||
// whole file.
|
||||
Undecoded []string `toml:"-"`
|
||||
}
|
||||
|
||||
// Load читает манифест набора из директории root.
|
||||
// Load reads the suite manifest from directory root.
|
||||
func Load(root string) (*Manifest, error) {
|
||||
path := filepath.Join(root, Name)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("чтение манифеста набора: %w", err)
|
||||
return nil, fmt.Errorf("reading the suite manifest: %w", err)
|
||||
}
|
||||
|
||||
var m Manifest
|
||||
meta, err := toml.Decode(string(data), &m)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("разбор %s: %w", path, err)
|
||||
return nil, fmt.Errorf("parsing %s: %w", path, err)
|
||||
}
|
||||
m.Path = path
|
||||
for _, key := range meta.Undecoded() {
|
||||
@@ -81,8 +84,8 @@ func Load(root string) (*Manifest, error) {
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// Find поднимается от start вверх до корня, ища директорию с манифестом
|
||||
// набора. Так `convy suite check` работает из любой поддиректории набора.
|
||||
// Find walks up from start looking for a directory that holds a suite
|
||||
// manifest, so that `convy suite check` works from any subdirectory of a suite.
|
||||
func Find(start string) (string, error) {
|
||||
dir, err := filepath.Abs(start)
|
||||
if err != nil {
|
||||
@@ -100,22 +103,22 @@ func Find(start string) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ErrNotFound означает, что рядом и выше нет манифеста набора.
|
||||
var ErrNotFound = errors.New("манифест набора не найден")
|
||||
// ErrNotFound means there is no suite manifest here or above.
|
||||
var ErrNotFound = errors.New("suite manifest not found")
|
||||
|
||||
// LivePrefixes перечисляет живые префиксы в порядке, устойчивом между
|
||||
// запусками: вывод проверки не должен зависеть от обхода карты.
|
||||
// LivePrefixes lists the live prefixes in an order stable between runs: the
|
||||
// output of a check must not depend on map iteration.
|
||||
func (m *Manifest) LivePrefixes() []string {
|
||||
return sortedKeys(m.Prefixes.Live)
|
||||
}
|
||||
|
||||
// LiveTopics перечисляет живые темы в устойчивом порядке.
|
||||
// LiveTopics lists the live topics in a stable order.
|
||||
func (m *Manifest) LiveTopics() []string {
|
||||
return sortedKeys(m.Topics.Live)
|
||||
}
|
||||
|
||||
// PrefixOf возвращает префикс, объявленный за файлом, если такой есть.
|
||||
// Путь сверяется в форме со слэшами — так он записан в манифесте.
|
||||
// PrefixOf returns the prefix declared for a file, if there is one. Paths are
|
||||
// compared in slash form, the way the manifest writes them.
|
||||
func (m *Manifest) PrefixOf(path string) (string, bool) {
|
||||
want := filepath.ToSlash(path)
|
||||
for prefix, declared := range m.Prefixes.Live {
|
||||
@@ -126,44 +129,44 @@ func (m *Manifest) PrefixOf(path string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// PathOf возвращает путь, объявленный за живым префиксом.
|
||||
// PathOf returns the path declared for a live prefix.
|
||||
func (m *Manifest) PathOf(prefix string) (string, bool) {
|
||||
path, ok := m.Prefixes.Live[prefix]
|
||||
return path, ok
|
||||
}
|
||||
|
||||
// TopicLive отвечает, объявлена ли тема среди живых.
|
||||
// TopicLive reports whether the topic is declared among the live ones.
|
||||
func (m *Manifest) TopicLive(topic string) bool {
|
||||
_, ok := m.Topics.Live[topic]
|
||||
return ok
|
||||
}
|
||||
|
||||
// TopicRetired отвечает, значится ли тема среди выбывших.
|
||||
// TopicRetired reports whether the topic is listed among the retired ones.
|
||||
func (m *Manifest) TopicRetired(topic string) bool {
|
||||
_, ok := m.Topics.Retired[topic]
|
||||
return ok
|
||||
}
|
||||
|
||||
// PrefixRetired отвечает, значится ли префикс среди выбывших.
|
||||
// PrefixRetired reports whether the prefix is listed among the retired ones.
|
||||
func (m *Manifest) PrefixRetired(prefix string) bool {
|
||||
_, ok := m.Prefixes.Retired[prefix]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ValidPrefix проверяет форму префикса: четыре заглавные латинские буквы.
|
||||
// Буква X в начале зарезервирована за репозиториями-потребителями, и набор
|
||||
// её не занимает никогда.
|
||||
// ValidPrefix checks the shape of a prefix: four uppercase Latin letters. The
|
||||
// letter X in first position is reserved for consuming repositories, and the
|
||||
// suite never takes it.
|
||||
func ValidPrefix(prefix string) error {
|
||||
if len(prefix) != 4 {
|
||||
return fmt.Errorf("префикс %q — не четыре буквы", prefix)
|
||||
return fmt.Errorf("prefix %q is not four letters", prefix)
|
||||
}
|
||||
for _, r := range prefix {
|
||||
if r < 'A' || r > 'Z' {
|
||||
return fmt.Errorf("префикс %q содержит не заглавную латинскую букву", prefix)
|
||||
return fmt.Errorf("prefix %q holds a character that is not an uppercase Latin letter", prefix)
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(prefix, "X") {
|
||||
return fmt.Errorf("префикс %q начинается на X — буква зарезервирована за локальными правилами потребителей", prefix)
|
||||
return fmt.Errorf("prefix %q starts with X, a letter reserved for the local rules of consumers", prefix)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user