suite init и suite add: заведение набора и конвенции в двух режимах
- suite init создаёт директорию и манифест со скелетом таблиц; suite add пишет файл конвенции и вправляет запись в suite.toml, сохраняя комментарии - без аргументов команды спрашивают поля с подсказками, с флагами берут всё сразу и не спрашивают ничего; без терминала пустой вызов отказывает - строка о версии языка генерируется из словаря набора, поэтому созданный файл проходит suite check без правок - починено разрешение extends: короткая форма бралась по суффиксу и могла указать на сам файл; теперь неоднозначность либо избегается при записи, либо сообщается ошибкой
This commit is contained in:
+51
-10
@@ -3,6 +3,7 @@ package check
|
||||
import (
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.vakhrushev.me/av/convy/internal/doc"
|
||||
@@ -74,7 +75,13 @@ func checkExtends(s *suite.Suite, d *doc.Document, rep *Report) {
|
||||
return
|
||||
}
|
||||
at := d.Front.At["extends"]
|
||||
target := resolveExtends(s, d.Front.Extends)
|
||||
target, others := resolveExtends(s, d, d.Front.Extends)
|
||||
if len(others) > 1 {
|
||||
rep.Errorf(Spread, d.Path, at,
|
||||
"extends points at %q, and the suite holds several files it could mean (%v): give the path from the root of the suite",
|
||||
d.Front.Extends, others)
|
||||
return
|
||||
}
|
||||
if target == nil {
|
||||
rep.Errorf(Spread, d.Path, at,
|
||||
"extends points at %q, and the suite holds no such file", d.Front.Extends)
|
||||
@@ -91,17 +98,52 @@ func checkExtends(s *suite.Suite, d *doc.Document, rep *Report) {
|
||||
}
|
||||
}
|
||||
|
||||
// resolveExtends looks up the document at the path written in extends. The path
|
||||
// is given from the conventions directory, so both it and a path from the root
|
||||
// of the suite are tried.
|
||||
func resolveExtends(s *suite.Suite, ref string) *doc.Document {
|
||||
// resolveExtends looks up the document at the path written in extends.
|
||||
//
|
||||
// The path may be given from the root of the suite or from the directory of
|
||||
// conventions, so an exact match is tried first and a tail match second. A tail
|
||||
// match can fit several files at once — two layers of one topic often share a
|
||||
// file name — so every candidate is returned and the caller reports the
|
||||
// ambiguity instead of picking by the order documents happen to be loaded in.
|
||||
// The document doing the extending is never its own base.
|
||||
func resolveExtends(s *suite.Suite, from *doc.Document, ref string) (*doc.Document, []string) {
|
||||
ref = path.Clean(strings.TrimPrefix(ref, "./"))
|
||||
var candidates []*doc.Document
|
||||
for _, d := range s.Docs {
|
||||
if d.Path == ref || strings.HasSuffix(d.Path, "/"+ref) {
|
||||
return d
|
||||
if d == from {
|
||||
continue
|
||||
}
|
||||
if d.Path == ref {
|
||||
return d, []string{d.Path}
|
||||
}
|
||||
if strings.HasSuffix(d.Path, "/"+ref) {
|
||||
candidates = append(candidates, d)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
paths := make([]string, len(candidates))
|
||||
for i, d := range candidates {
|
||||
paths[i] = d.Path
|
||||
}
|
||||
sort.Strings(paths)
|
||||
if len(candidates) == 1 {
|
||||
return candidates[0], paths
|
||||
}
|
||||
return nil, paths
|
||||
}
|
||||
|
||||
// namesSuiteFile reports whether a candidate written in the text names a file
|
||||
// the suite holds. Unlike an extends key it needs no single answer: a path that
|
||||
// fits several files of the canon is a path all the same.
|
||||
func namesSuiteFile(s *suite.Suite, candidate string) bool {
|
||||
if s.Exists(candidate) {
|
||||
return true
|
||||
}
|
||||
for _, d := range s.Docs {
|
||||
if d.Path == candidate || strings.HasSuffix(d.Path, "/"+candidate) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// checkMechanized looks for the mark of mechanization in the text of a
|
||||
@@ -142,8 +184,7 @@ func checkCanonPaths(s *suite.Suite, d *doc.Document, rep *Report) {
|
||||
continue
|
||||
}
|
||||
for _, candidate := range mdPathRe.FindAllString(d.Line(n), -1) {
|
||||
target := resolveExtends(s, candidate)
|
||||
if target == nil && !s.Exists(candidate) {
|
||||
if !namesSuiteFile(s, candidate) {
|
||||
continue
|
||||
}
|
||||
rep.Errorf(Spread, d.Path, n,
|
||||
|
||||
Reference in New Issue
Block a user