github.com/JarrahG/buffalocli@v0.0.0-20230801092127-b85bfd5d395a/internal/genny/build/validate.go (about) 1 package build 2 3 import ( 4 "errors" 5 "fmt" 6 "html/template" 7 "io/fs" 8 "strings" 9 10 "github.com/gobuffalo/genny/v2" 11 "github.com/gobuffalo/plush/v4" 12 ) 13 14 // TemplateValidator is given a file and returns an 15 // effort if there is a template validation error 16 // with the template 17 type TemplateValidator func(f genny.File) error 18 19 // ValidateTemplates returns a genny.RunFn that will walk the 20 // given filesystem and run each of the files found through each of the 21 // template validators 22 func ValidateTemplates(fsys fs.FS, tvs []TemplateValidator) genny.RunFn { 23 if len(tvs) == 0 { 24 return func(r *genny.Runner) error { 25 return nil 26 } 27 } 28 return func(r *genny.Runner) error { 29 var errs []string 30 err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { 31 if err != nil { 32 return err 33 } 34 35 if d.IsDir() { 36 return nil 37 } 38 39 b, err := fsys.Open(path) 40 if err != nil { 41 return err 42 } 43 f := genny.NewFile(path, b) 44 for _, tv := range tvs { 45 err := safeRun(func() { 46 if err := tv(f); err != nil { 47 errs = append(errs, fmt.Sprintf("template error in file %s: %s", path, err.Error())) 48 } 49 }) 50 if err != nil { 51 return err 52 } 53 } 54 55 return nil 56 }) 57 if err != nil { 58 return err 59 } 60 if len(errs) == 0 { 61 return nil 62 } 63 return fmt.Errorf(strings.Join(errs, "\n")) 64 } 65 } 66 67 // PlushValidator validates the file is a valid 68 // Plush file if the extension is .md, .html, or .plush 69 func PlushValidator(f genny.File) error { 70 if !genny.HasExt(f, ".html", ".md", ".plush") { 71 return nil 72 } 73 _, err := plush.Parse(f.String()) 74 return err 75 } 76 77 // GoTemplateValidator validates the file is a 78 // valid Go text/template file if the extension 79 // is .tmpl 80 func GoTemplateValidator(f genny.File) error { 81 if !genny.HasExt(f, ".tmpl") { 82 return nil 83 } 84 t := template.New(f.Name()) 85 _, err := t.Parse(f.String()) 86 return err 87 } 88 89 // safeRun the function safely knowing that if it panics 90 // the panic will be caught and returned as an error 91 func safeRun(fn func()) (err error) { 92 defer func() { 93 if ex := recover(); ex != nil { 94 if e, ok := ex.(error); ok { 95 err = e 96 return 97 } 98 err = errors.New(fmt.Sprint(ex)) 99 } 100 }() 101 102 fn() 103 return nil 104 }