Public Access
feat: scaffold API, client, or monorepo projects with Nuxt/Vue client support
- draft new now offers API, Client, or Full Stack (monorepo) project shapes - draft new client scaffolds a Nuxt or Vue app via the official nuxi/create-vue tooling, with a Draft-maintained auth/API overlay layered on top - draft new monorepo combines a scaffolded API and client under one root with go.work, pnpm-workspace.yaml, and docker-compose wiring - assets/embedded restructured into api/monorepo-root/client-nuxt/client-vue zones, synced via a generalized, job-based sync tool
This commit is contained in:
1 parent
fe48b7caee
commit
29f94539e0
7 files changed
+724
-99
No files matched your search
+92
-30
@@ -3,67 +3,129 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
sourceDir = "assets/testdata/api_tmpl"
|
||||
targetDir = "assets/embedded"
|
||||
oldModuleName = "github.com/FernandoJVideira/api_tmpl"
|
||||
oldModuleName = "app_tmpl"
|
||||
moduleTemplate = "{{ .ModuleName }}"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("Syncing templates...")
|
||||
syncTemplates()
|
||||
type syncJob struct {
|
||||
templateName string // optional, for logging purposes
|
||||
sourceDir string
|
||||
targetDir string
|
||||
excludePrefix string // relative-path prefix to skip, e.g. "apps/"; empty = sync everything
|
||||
includePrefixes []string // if set, only paths with one of these prefixes sync; empty = sync everything
|
||||
}
|
||||
|
||||
func syncTemplates() {
|
||||
var jobs = []syncJob{
|
||||
{
|
||||
templateName: "api",
|
||||
sourceDir: "assets/testdata/template/apps/api",
|
||||
targetDir: "assets/embedded/api",
|
||||
},
|
||||
{
|
||||
templateName: "monorepo-root",
|
||||
sourceDir: "assets/testdata/template",
|
||||
targetDir: "assets/embedded/monorepo-root",
|
||||
excludePrefix: "apps/",
|
||||
},
|
||||
{
|
||||
templateName: "client-nuxt",
|
||||
sourceDir: "assets/testdata/template/apps/client",
|
||||
targetDir: "assets/embedded/client-nuxt",
|
||||
includePrefixes: []string{"app/", "public/"},
|
||||
},
|
||||
{
|
||||
templateName: "client-vue",
|
||||
sourceDir: "assets/testdata/template/apps/vue-client",
|
||||
targetDir: "assets/embedded/client-vue",
|
||||
includePrefixes: []string{
|
||||
"src/App.vue",
|
||||
"src/main.ts",
|
||||
"src/router/",
|
||||
"src/stores/",
|
||||
"src/composables/",
|
||||
"src/lib/api-client.ts",
|
||||
"src/components/AppBrand.vue",
|
||||
"src/components/AppLayout.vue",
|
||||
"src/views/",
|
||||
"src/shared/",
|
||||
".env.example",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := filepath.WalkDir(sourceDir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func main() {
|
||||
log.Println("Syncing templates...")
|
||||
for _, job := range jobs {
|
||||
syncTemplates(job)
|
||||
}
|
||||
}
|
||||
|
||||
relPath, _ := filepath.Rel(sourceDir, path)
|
||||
destPath := filepath.Join(targetDir, relPath)
|
||||
func syncTemplates(job syncJob) {
|
||||
|
||||
if strings.HasPrefix(d.Name(), ".") && d.Name() != "." {
|
||||
if d.IsDir() {
|
||||
return filepath.SkipDir
|
||||
err := os.RemoveAll(job.targetDir)
|
||||
if err != nil {
|
||||
log.Fatalf("Error removing target directory: %v", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command("git", "-C", job.sourceDir, "ls-files")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Fatalf("Error listing files in source directory: %v", err)
|
||||
}
|
||||
|
||||
paths := strings.Split(strings.TrimSpace(string(output)), "\n")
|
||||
|
||||
for _, relPath := range paths {
|
||||
|
||||
if len(job.includePrefixes) > 0 {
|
||||
included := false
|
||||
for _, prefix := range job.includePrefixes {
|
||||
if strings.HasPrefix(relPath, prefix) {
|
||||
included = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
if !included {
|
||||
continue
|
||||
}
|
||||
} else if job.excludePrefix != "" && strings.HasPrefix(relPath, job.excludePrefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
return os.MkdirAll(destPath, 0755)
|
||||
srcPath := filepath.Join(job.sourceDir, relPath)
|
||||
destPath := filepath.Join(job.targetDir, relPath)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
|
||||
log.Fatalf("Error creating destination directory: %v", err)
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(path)
|
||||
content, err := os.ReadFile(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
log.Fatalf("Error reading source file: %v", err)
|
||||
}
|
||||
|
||||
if d.Name() == "go.mod" || d.Name() == "go.sum" {
|
||||
if filepath.Base(relPath) == "go.mod" || filepath.Base(relPath) == "go.sum" {
|
||||
destPath += ".tmpl"
|
||||
}
|
||||
|
||||
if d.Name() == "go.mod" {
|
||||
if filepath.Base(relPath) == "go.mod" {
|
||||
strContent := string(content)
|
||||
strContent = strings.Replace(strContent, oldModuleName, moduleTemplate, 1)
|
||||
content = []byte(strContent)
|
||||
}
|
||||
|
||||
return os.WriteFile(destPath, content, 0644)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error walking source: %v", err)
|
||||
if err := os.WriteFile(destPath, content, 0644); err != nil {
|
||||
log.Fatalf("Error writing to destination file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Templates synced successfully!")
|
||||
log.Printf("Template %s synced successfully!", job.templateName)
|
||||
}
|
||||
Reference in new issue
Block a user