From 572a486f4f04900826512cd818b68941ec930a18 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 24 Sep 2023 19:16:00 +0800 Subject: [PATCH] [add] Page Builder API (15%) --- sui/core/types.go | 16 +++- sui/storages/azure/azure.go | 47 ++++++------ sui/storages/local/local.go | 55 +++++++++++++- sui/storages/local/local_test.go | 16 ++++ sui/storages/local/template.go | 111 +++++++++++++++++----------- sui/storages/local/template_test.go | 61 +++++++++++++++ sui/storages/local/types.go | 4 +- sui/sui.go | 4 +- sui/sui_test.go | 2 + 9 files changed, 242 insertions(+), 74 deletions(-) create mode 100644 sui/storages/local/template_test.go diff --git a/sui/core/types.go b/sui/core/types.go index f833b111..ca22b1a3 100644 --- a/sui/core/types.go +++ b/sui/core/types.go @@ -9,9 +9,19 @@ type SUI interface { // Page is the struct for the page type Page struct { - template *Template - route string - file string + Route string `json:"route"` + Root string `json:"root"` + Files PageFiles `json:"files"` +} + +// PageFiles is the struct for the page files +type PageFiles struct { + HTML string `json:"html"` + CSS string `json:"css"` + JS string `json:"js"` + TS string `json:"ts"` + LESS string `json:"less"` + DATA string `json:"data"` } // Component is the struct for the component diff --git a/sui/storages/azure/azure.go b/sui/storages/azure/azure.go index bbd5631f..20de84f5 100644 --- a/sui/storages/azure/azure.go +++ b/sui/storages/azure/azure.go @@ -1,55 +1,54 @@ package azure import ( - "fmt" "net/url" "github.com/yaoapp/yao/sui/core" ) -// Remote is the struct for the azure sui -type Remote struct{ url url.URL } +// Azure is the struct for the azure sui +type Azure struct{ url url.URL } // new create a new azure sui -func new(host url.URL) (*Remote, error) { - return &Remote{url: host}, nil +func new() (*Azure, error) { + return &Azure{}, nil } // New create a new azure sui -func New(dsl *core.DSL) (*Remote, error) { +func New(dsl *core.DSL) (*Azure, error) { - if dsl.Storage.Option == nil { - return nil, fmt.Errorf("option.host is required") - } + // if dsl.Storage.Option == nil { + // return nil, fmt.Errorf("option.host is required") + // } - if dsl.Storage.Option["host"] == nil { - return nil, fmt.Errorf("option.host is required") - } + // if dsl.Storage.Option["host"] == nil { + // return nil, fmt.Errorf("option.host is required") + // } - host, ok := dsl.Storage.Option["host"].(string) - if !ok { - return nil, fmt.Errorf("option.host %s is not a valid string", host) - } + // host, ok := dsl.Storage.Option["host"].(string) + // if !ok { + // return nil, fmt.Errorf("option.host %s is not a valid string", host) + // } - u, err := url.Parse(host) - if err != nil { - return nil, fmt.Errorf("option.host %s is not a valid url", host) - } + // u, err := url.Parse(host) + // if err != nil { + // return nil, fmt.Errorf("option.host %s is not a valid url", host) + // } - return new(*u) + return new() } // GetTemplates get the templates -func (azure *Remote) GetTemplates() ([]core.ITemplate, error) { +func (azure *Azure) GetTemplates() ([]core.ITemplate, error) { return nil, nil } // GetTemplate get the template -func (azure *Remote) GetTemplate(name string) (core.ITemplate, error) { +func (azure *Azure) GetTemplate(name string) (core.ITemplate, error) { return nil, nil } // UploadTemplate upload the template -func (azure *Remote) UploadTemplate(src string, dst string) (core.ITemplate, error) { +func (azure *Azure) UploadTemplate(src string, dst string) (core.ITemplate, error) { return nil, nil } diff --git a/sui/storages/local/local.go b/sui/storages/local/local.go index af6c463d..30083e49 100644 --- a/sui/storages/local/local.go +++ b/sui/storages/local/local.go @@ -1,8 +1,15 @@ package local import ( + "fmt" + "path" + "path/filepath" + "strings" + + jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou/fs" "github.com/yaoapp/kun/log" + "github.com/yaoapp/yao/sui/core" sui "github.com/yaoapp/yao/sui/core" ) @@ -63,7 +70,7 @@ func (local *Local) GetTemplates() ([]sui.ITemplate, error) { continue } - tmpl, err := local.NewTemplate(dir) + tmpl, err := local.getTemplateFrom(dir) if err != nil { log.Error("GetTemplates %s error: %s", dir, err.Error()) continue @@ -75,11 +82,53 @@ func (local *Local) GetTemplates() ([]sui.ITemplate, error) { } // GetTemplate get the template -func (local *Local) GetTemplate(name string) (sui.ITemplate, error) { - return nil, nil +func (local *Local) GetTemplate(id string) (sui.ITemplate, error) { + path := path.Join(local.root, id) + return local.getTemplate(id, path) } // UploadTemplate upload the template func (local *Local) UploadTemplate(src string, dst string) (sui.ITemplate, error) { return nil, nil } + +// GetTemplateFrom get the template from the path +func (local *Local) getTemplateFrom(path string) (*Template, error) { + id := local.getTemplateID(path) + return local.getTemplate(id, path) +} + +// getTemplate get the template +func (local *Local) getTemplate(id string, path string) (*Template, error) { + + tmpl := Template{ + local: local, + Root: path, + Template: &core.Template{ + ID: id, + Name: strings.ToUpper(id), + Version: 1, + Screenshots: []string{}, + }} + + // load the template.json + configFile := filepath.Join(path, fmt.Sprintf("%s.json", id)) + if local.fs.IsFile(configFile) { + configBytes, err := local.fs.ReadFile(configFile) + if err != nil { + return nil, err + } + + err = jsoniter.Unmarshal(configBytes, &tmpl.Template) + if err != nil { + return nil, err + } + } + + return &tmpl, nil +} + +// GetTemplateID get the template ID +func (local *Local) getTemplateID(path string) string { + return filepath.Base(path) +} diff --git a/sui/storages/local/local_test.go b/sui/storages/local/local_test.go index cd3c0686..b641f258 100644 --- a/sui/storages/local/local_test.go +++ b/sui/storages/local/local_test.go @@ -36,6 +36,22 @@ func TestGetTemplates(t *testing.T) { } +func TestGetTemplate(t *testing.T) { + tests := prepare(t) + defer clean() + + websiteAI, err := tests.Demo.GetTemplate("website-ai") + if err != nil { + t.Fatalf("GetTemplate error: %v", err) + } + + assert.Equal(t, "website-ai", websiteAI.(*Template).ID) + assert.Equal(t, "Website DEMO", websiteAI.(*Template).Name) + assert.Equal(t, true, len(websiteAI.(*Template).Screenshots) > 0) + assert.Equal(t, 2, websiteAI.(*Template).Version) + assert.Equal(t, "AI Website DEMO", websiteAI.(*Template).Descrption) +} + func prepare(t *testing.T) struct { Demo *Local Screen *Local diff --git a/sui/storages/local/template.go b/sui/storages/local/template.go index 9ccd5723..25d52643 100644 --- a/sui/storages/local/template.go +++ b/sui/storages/local/template.go @@ -5,45 +5,10 @@ import ( "path/filepath" "strings" - jsoniter "github.com/json-iterator/go" + "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/sui/core" ) -// NewTemplate create a new local template -func (local *Local) NewTemplate(path string) (*Template, error) { - id := local.GetTemplateID(path) - - tmpl := Template{ - Path: path, - Template: &core.Template{ - ID: id, - Name: strings.ToUpper(id), - Version: 1, - Screenshots: []string{}, - }} - - // load the template.json - configFile := filepath.Join(path, fmt.Sprintf("%s.json", id)) - if local.fs.IsFile(configFile) { - configBytes, err := local.fs.ReadFile(configFile) - if err != nil { - return nil, err - } - - err = jsoniter.Unmarshal(configBytes, &tmpl.Template) - if err != nil { - return nil, err - } - } - - return &tmpl, nil -} - -// GetTemplateID get the template ID -func (local *Local) GetTemplateID(path string) string { - return filepath.Base(path) -} - // Get get the template func (tmpl *Template) Get() error { return nil @@ -56,7 +21,74 @@ func (tmpl *Template) Save() error { // Pages get the pages func (tmpl *Template) Pages() ([]core.IPage, error) { - return nil, nil + + exts := []string{"*.sui", "*.html", "*.htm", "*.page"} + pages := []core.IPage{} + tmpl.local.fs.Walk(tmpl.Root, func(root, file string, isdir bool) error { + name := filepath.Base(file) + if isdir { + if strings.HasPrefix(name, "__") { + return filepath.SkipDir + } + return nil + } + + if strings.HasPrefix(name, "__") { + return nil + } + + page, err := tmpl.getPageFrom(file) + if err != nil { + log.Error("Get page error: %v", err) + return nil + } + + pages = append(pages, page) + return nil + }, exts...) + + return pages, nil +} + +// Page get the page +func (tmpl *Template) Page(route string) (core.IPage, error) { + path := filepath.Join(tmpl.Root, route) + exts := []string{".sui", ".html", ".htm", ".page"} + for _, ext := range exts { + file := fmt.Sprintf("%s%s", path, ext) + if exist, _ := tmpl.local.fs.Exists(file); exist { + return tmpl.getPageFrom(file) + } + } + return nil, fmt.Errorf("Page %s not found", route) +} + +func (tmpl *Template) getPageFrom(path string) (core.IPage, error) { + route := tmpl.getPageRoute(path) + return tmpl.getPage(route, path) +} + +func (tmpl *Template) getPage(route, file string) (core.IPage, error) { + root := filepath.Dir(file) + return &Page{ + tmpl: tmpl, + Page: &core.Page{ + Route: route, + Root: root, + Files: core.PageFiles{ + HTML: fmt.Sprintf("%s%s", route, filepath.Ext(file)), + CSS: fmt.Sprintf("%s.css", route), + JS: fmt.Sprintf("%s.js", route), + DATA: fmt.Sprintf("%s.json", route), + TS: fmt.Sprintf("%s.ts", route), + LESS: fmt.Sprintf("%s.less", route), + }, + }, + }, nil +} + +func (tmpl *Template) getPageRoute(path string) string { + return strings.TrimSuffix(path[len(tmpl.Root):], filepath.Ext(path)) } // Blocks get the blocks @@ -69,11 +101,6 @@ func (tmpl *Template) Components() ([]core.IComponent, error) { return nil, nil } -// Page get the page -func (tmpl *Template) Page(route string) (core.IPage, error) { - return nil, nil -} - // Block get the block func (tmpl *Template) Block(name string) (core.IBlock, error) { return nil, nil diff --git a/sui/storages/local/template_test.go b/sui/storages/local/template_test.go new file mode 100644 index 00000000..4db652d2 --- /dev/null +++ b/sui/storages/local/template_test.go @@ -0,0 +1,61 @@ +package local + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTemplatePages(t *testing.T) { + tests := prepare(t) + defer clean() + + tmpl, err := tests.Demo.GetTemplate("website-ai") + if err != nil { + t.Fatalf("GetTemplate error: %v", err) + } + + pages, err := tmpl.Pages() + if err != nil { + t.Fatalf("Pages error: %v", err) + } + + if len(pages) < 1 { + t.Fatalf("Pages error: %v", len(pages)) + } + + assert.Equal(t, "/index", pages[0].(*Page).Route) + assert.Equal(t, "/templates/website-ai", pages[0].(*Page).Root) + assert.Equal(t, "/index.css", pages[0].(*Page).Files.CSS) + assert.Equal(t, "/index.html", pages[0].(*Page).Files.HTML) + assert.Equal(t, "/index.js", pages[0].(*Page).Files.JS) + assert.Equal(t, "/index.less", pages[0].(*Page).Files.LESS) + assert.Equal(t, "/index.ts", pages[0].(*Page).Files.TS) + assert.Equal(t, "/index.json", pages[0].(*Page).Files.DATA) +} + +func TestTemplatePage(t *testing.T) { + tests := prepare(t) + defer clean() + + tmpl, err := tests.Demo.GetTemplate("website-ai") + if err != nil { + t.Fatalf("GetTemplate error: %v", err) + } + + page, err := tmpl.Page("/index") + if err != nil { + t.Fatalf("Page error: %v", err) + } + assert.Equal(t, "/index", page.(*Page).Route) + assert.Equal(t, "/templates/website-ai", page.(*Page).Root) + assert.Equal(t, "/index.css", page.(*Page).Files.CSS) + assert.Equal(t, "/index.html", page.(*Page).Files.HTML) + assert.Equal(t, "/index.js", page.(*Page).Files.JS) + assert.Equal(t, "/index.less", page.(*Page).Files.LESS) + assert.Equal(t, "/index.ts", page.(*Page).Files.TS) + assert.Equal(t, "/index.json", page.(*Page).Files.DATA) + + _, err = tmpl.Page("/the/page/could/not/be/found") + assert.Contains(t, err.Error(), "Page /the/page/could/not/be/found not found") +} diff --git a/sui/storages/local/types.go b/sui/storages/local/types.go index 2405bc1e..40d2c5c7 100644 --- a/sui/storages/local/types.go +++ b/sui/storages/local/types.go @@ -14,12 +14,14 @@ type Local struct { // Template is the struct for the local sui template type Template struct { - Path string `json:"-"` + Root string `json:"-"` + local *Local *core.Template } // Page is the struct for the local sui page type Page struct { + tmpl *Template *core.Page } diff --git a/sui/sui.go b/sui/sui.go index 26494e44..aacffb56 100644 --- a/sui/sui.go +++ b/sui/sui.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/yaoapp/gou/application" + "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/share" "github.com/yaoapp/yao/sui/core" @@ -37,7 +38,7 @@ func New(dsl *core.DSL) (core.SUI, error) { // Load load the sui func Load(cfg config.Config) error { - exts := []string{"*.core.yao", "*.core.jsonc", "*.core.json"} + exts := []string{"*.sui.yao", "*.sui.jsonc", "*.sui.json"} return application.App.Walk("suis", func(root, file string, isdir bool) error { if isdir { return nil @@ -46,6 +47,7 @@ func Load(cfg config.Config) error { id := share.ID(root, file) _, err := loadFile(file, id) if err != nil { + log.Error("[sui] Load sui %s error: %s", id, err.Error()) return err } return nil diff --git a/sui/sui_test.go b/sui/sui_test.go index 02f18b81..8e36b93b 100644 --- a/sui/sui_test.go +++ b/sui/sui_test.go @@ -16,6 +16,8 @@ func TestLoad(t *testing.T) { if err != nil { t.Fatal(err) } + + check(t) } func check(t *testing.T) {