Skip to content

Commit

Permalink
Modify expected structure of template FS
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenafamo committed Dec 12, 2024
1 parent 660c076 commit 329d1db
Show file tree
Hide file tree
Showing 32 changed files with 66 additions and 76 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Collation in `clause.OrderDef` is now a string not an expression and is always quoted
- Calling `UpdateAll`, `DeleteAll` and `ReloadAll` on an empty model slice now returns nil without running any queries.
- Generated files now end with `.bob.go` instead of `.go` and are always cleaned up before generating new files. Singleton templates are now required to have a `.bob.go.tpl` extension.
- The expected structure for templates have been changed:
- Previously, singleton templates should be kept in a `singleton` folder. Now, any template not inside a folder is considered a singleton template.
- Previoulsy, templates in the root folder are merged and run for each table. Now, this will happen to templates in the `table/` folder.
- Previoulsy, the entire file tree and every subdirectory is walked to find templates. Now only templates in the root folder and the `table/` folder are considered.

### Deprecated

Expand Down
17 changes: 2 additions & 15 deletions gen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,32 +190,19 @@ func generate[T, C, I any](s *State[C], data *TemplateData[T, C, I], goVersion s
o.templateByteBuffer = templateByteBuffer
o.templateHeaderByteBuffer = templateHeaderByteBuffer

if err := generateSingletonOutput(o, data, goVersion); err != nil {
if err := generateSingletonOutput(o, data, goVersion, s.Config.NoTests); err != nil {
return fmt.Errorf("singleton template output: %w", err)
}

if !s.Config.NoTests {
if err := generateSingletonTestOutput(o, data, goVersion); err != nil {
return fmt.Errorf("unable to generate singleton test template output: %w", err)
}
}

dirExtMap := groupTemplates(o.tableTemplates)

for _, table := range data.Tables {
data.Table = table

// Generate the regular templates
if err := generateOutput(o, dirExtMap, data, goVersion); err != nil {
if err := generateOutput(o, dirExtMap, data, goVersion, s.Config.NoTests); err != nil {
return fmt.Errorf("unable to generate output: %w", err)
}

// Generate the test templates
if !s.Config.NoTests {
if err := generateTestOutput(o, dirExtMap, data, goVersion); err != nil {
return fmt.Errorf("unable to generate test output: %w", err)
}
}
}
}

Expand Down
101 changes: 52 additions & 49 deletions gen/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,18 @@ func (o *Output) initTemplates(funcs template.FuncMap) error {
o.singletonTemplates = template.New("")
o.tableTemplates = template.New("")

if err := addTemplates(o.singletonTemplates, o.Templates, funcs, "singleton"); err != nil {
if err := addTemplates(o.singletonTemplates, o.Templates, funcs, ".", true); err != nil {
return fmt.Errorf("failed to add singleton templates: %w", err)
}

if err := addTemplates(o.tableTemplates, o.Templates, funcs, "."); err != nil {
if err := addTemplates(o.tableTemplates, o.Templates, funcs, "table", false); err != nil {
return fmt.Errorf("failed to add table templates: %w", err)
}

return nil
}

func addTemplates(tpl *template.Template, tempFSs []fs.FS, funcs template.FuncMap, dir string) error {
func addTemplates(tpl *template.Template, tempFSs []fs.FS, funcs template.FuncMap, dir string, singletons bool) error {
all := make(map[string]fs.FS)
for _, tempFS := range tempFSs {
if tempFS == nil {
Expand All @@ -154,10 +154,20 @@ func addTemplates(tpl *template.Template, tempFSs []fs.FS, funcs template.FuncMa
}

path := entry.Name()
if filepath.Ext(path) != ".tpl" {
ext := filepath.Ext(path)
if ext != ".tpl" {
continue
}

if singletons {
ext2 := filepath.Ext(path[:len(path)-len(ext)])
fNameWithoutExts := filepath.Base(path[:len(path)-len(ext)-len(ext2)])
if !strings.HasSuffix(fNameWithoutExts, ".bob") &&
!strings.HasSuffix(fNameWithoutExts, ".bob_test") {
panic(fmt.Sprintf("singleton file name must end with .bob or .bob_test: %s", path))
}
}

all[filepath.Join(dir, path)] = tempFS
}
}
Expand All @@ -171,7 +181,7 @@ func addTemplates(tpl *template.Template, tempFSs []fs.FS, funcs template.FuncMa
return fmt.Errorf("failed to read template: %s: %w", path, err)
}

err = loadTemplate(tpl, funcs, normalizeSlashes(path), string(content))
err = loadTemplate(tpl, funcs, filepath.Base(path), string(content))
if err != nil {
return fmt.Errorf("failed to load template: %s: %w", path, err)
}
Expand All @@ -189,43 +199,56 @@ type executeTemplateData[T, C, I any] struct {
}

// generateOutput builds the file output and sends it to outHandler for saving
func generateOutput[T, C, I any](o *Output, dirExts dirExtMap, data *TemplateData[T, C, I], goVersion string) error {
return executeTemplates(executeTemplateData[T, C, I]{
func generateOutput[T, C, I any](o *Output, dirExts dirExtMap, data *TemplateData[T, C, I], goVersion string, noTests bool) error {
if err := executeTemplates(executeTemplateData[T, C, I]{
output: o,
data: data,
templates: o.tableTemplates,
dirExtensions: dirExts,
}, goVersion, false)
}
}, goVersion, false); err != nil {
return fmt.Errorf("execute templates: %w", err)
}

if noTests {
return nil
}

// generateTestOutput builds the test file output and sends it to outHandler for saving
func generateTestOutput[T, C, I any](o *Output, dirExts dirExtMap, data *TemplateData[T, C, I], goVersion string) error {
return executeTemplates(executeTemplateData[T, C, I]{
if err := executeTemplates(executeTemplateData[T, C, I]{
output: o,
data: data,
templates: o.tableTemplates,
dirExtensions: dirExts,
}, goVersion, true)
}, goVersion, true); err != nil {
return fmt.Errorf("execute test templates: %w", err)
}

return nil
}

// generateSingletonOutput processes the templates that should only be run
// one time.
func generateSingletonOutput[T, C, I any](o *Output, data *TemplateData[T, C, I], goVersion string) error {
return executeSingletonTemplates(executeTemplateData[T, C, I]{
func generateSingletonOutput[T, C, I any](o *Output, data *TemplateData[T, C, I], goVersion string, noTests bool) error {
if err := executeSingletonTemplates(executeTemplateData[T, C, I]{
output: o,
data: data,
templates: o.singletonTemplates,
}, goVersion, false)
}
}, goVersion, false); err != nil {
return fmt.Errorf("execute singleton templates: %w", err)
}

// generateSingletonTestOutput processes the templates that should only be run
// one time.
func generateSingletonTestOutput[T, C, I any](o *Output, data *TemplateData[T, C, I], goVersion string) error {
return executeSingletonTemplates(executeTemplateData[T, C, I]{
if noTests {
return nil
}

if err := executeSingletonTemplates(executeTemplateData[T, C, I]{
output: o,
data: data,
templates: o.singletonTemplates,
}, goVersion, true)
}, goVersion, true); err != nil {
return fmt.Errorf("execute singleton test templates: %w", err)
}

return nil
}

func executeTemplates[T, C, I any](e executeTemplateData[T, C, I], goVersion string, tests bool) error {
Expand Down Expand Up @@ -316,7 +339,7 @@ func executeSingletonTemplates[T, C, I any](e executeTemplateData[T, C, I], goVe
continue
}

normalized, _, isGo := outputFilenameParts(tpl.Name())
normalized, isGo := outputFilenameParts(tpl.Name())

headerOut.Reset()
out.Reset()
Expand Down Expand Up @@ -516,35 +539,19 @@ func stringSliceToMap(slice []string) map[string]struct{} {
// templates_test/js/hello.js.tpl
//
//nolint:nonamedreturns
func outputFilenameParts(filename string) (normalized string, isSingleton, isGo bool) {
func outputFilenameParts(filename string) (normalized string, isGo bool) {
fragments := strings.Split(filename, string(os.PathSeparator))
isSingleton = len(fragments) > 1 && fragments[len(fragments)-2] == "singleton"

var remainingFragments []string
for _, f := range fragments {
if f != "singleton" {
remainingFragments = append(remainingFragments, f)
}
}

newFilename := remainingFragments[len(remainingFragments)-1]
newFilename := fragments[len(fragments)-1]
newFilename = strings.TrimSuffix(newFilename, ".tpl")
newFilename = rgxRemoveNumberedPrefix.ReplaceAllString(newFilename, "")
ext := filepath.Ext(newFilename)
isGo = ext == ".go"

remainingFragments[len(remainingFragments)-1] = newFilename
normalized = strings.Join(remainingFragments, string(os.PathSeparator))
fragments[len(fragments)-1] = newFilename
normalized = strings.Join(fragments, string(os.PathSeparator))

if isSingleton {
fNameWithoutExt := newFilename[:len(newFilename)-len(ext)]
if !strings.HasSuffix(fNameWithoutExt, ".bob") &&
!strings.HasSuffix(fNameWithoutExt, ".bob_test") {
panic(fmt.Sprintf("singleton file name must end with .bob or .bob_test: %s", filename))
}
}

return normalized, isSingleton, isGo
return normalized, isGo
}

type dirExtMap map[string]map[string][]string
Expand All @@ -559,11 +566,7 @@ func groupTemplates(templates *template.Template) dirExtMap {
continue
}

normalized, isSingleton, _ := outputFilenameParts(tpl.Name())
if isSingleton {
continue
}

normalized, _ := outputFilenameParts(tpl.Name())
dir := filepath.Dir(normalized)
if dir == "." {
dir = ""
Expand Down
20 changes: 8 additions & 12 deletions gen/output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,26 +63,22 @@ func TestOutputFilenameParts(t *testing.T) {
tests := []struct {
Filename string

Normalized string
IsSingleton bool
IsGo bool
Normalized string
IsGo bool
}{
{"00_struct.go.tpl", "struct.go", false, true},
{"singleton/00_struct.bob.go.tpl", "struct.bob.go", true, true},
{"notpkg/00_struct.go.tpl", "notpkg/struct.go", false, true},
{"js/singleton/00_struct.bob.js.tpl", "js/struct.bob.js", true, false},
{"js/00_struct.js.tpl", "js/struct.js", false, false},
{"00_struct.go.tpl", "struct.go", true},
{"singleton/00_struct.bob.go.tpl", "struct.bob.go", true},
{"notpkg/00_struct.go.tpl", "notpkg/struct.go", true},
{"js/singleton/00_struct.bob.js.tpl", "js/struct.bob.js", false},
{"js/00_struct.js.tpl", "js/struct.js", false},
}

for i, test := range tests {
normalized, isSingleton, isGo := outputFilenameParts(test.Filename)
normalized, isGo := outputFilenameParts(test.Filename)

if normalized != test.Normalized {
t.Errorf("%d) normalized wrong, want: %s, got: %s", i, test.Normalized, normalized)
}
if isSingleton != test.IsSingleton {
t.Errorf("%d) isSingleton wrong, want: %t, got: %t", i, test.IsSingleton, isSingleton)
}
if isGo != test.IsGo {
t.Errorf("%d) isGo wrong, want: %t, got: %t", i, test.IsGo, isGo)
}
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 329d1db

Please sign in to comment.