From 5b19ef3d19a54c7e835837654f2452e8848bac31 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 12 Jul 2024 08:39:57 +0800 Subject: [PATCH] refactor: Update BuildContext components to use boolean values instead of strings --- sui/core/build.go | 210 ++++++++++++++++++++++++++++++++++++++++++++ sui/core/compile.go | 182 ++++---------------------------------- sui/core/context.go | 2 +- sui/core/types.go | 2 +- sui/core/utils.go | 14 ++- 5 files changed, 241 insertions(+), 169 deletions(-) diff --git a/sui/core/build.go b/sui/core/build.go index a2f4a9af..cff6099b 100644 --- a/sui/core/build.go +++ b/sui/core/build.go @@ -12,6 +12,9 @@ import ( var slotRe = regexp.MustCompile(`\[\{([^\}]+)\}\]`) var cssRe = regexp.MustCompile(`([\.a-z0-9A-Z-:# ]+)\{`) +var transStmtReSingle = regexp.MustCompile(`'::([^:']+)'`) +var transStmtReDouble = regexp.MustCompile(`"::([^:"]+)"`) +var transFuncRe = regexp.MustCompile(`__m\s*\(\s*["'](.*?)["']\s*\)`) // Build build the page func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Document, []string, error) { @@ -73,6 +76,27 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume ctx.scripts = append(ctx.scripts, scripts...) ctx.styles = append(ctx.styles, styles...) + // Add the translation marks + sequence := 0 + err = page.TranslateMarks(ctx, doc, &sequence) + if err != nil { + return nil, warnings, err + } + + // Translate the scripts + if (scripts != nil) && len(scripts) > 0 { + for _, script := range scripts { + if script.Source == "" { + continue + } + trans, _, err := page.translateScript(script.Source, &sequence) + if err != nil { + return nil, ctx.warnings, err + } + ctx.translations = append(ctx.translations, trans...) + } + } + return doc, ctx.warnings, err } @@ -83,6 +107,10 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op return "", fmt.Errorf("The parent page is not set") } + if ctx == nil { + ctx = NewBuildContext(nil) + } + // Push the current page onto the stack and increment the visit counter ctx.stack = append(ctx.stack, page.Route) ctx.visited[page.Route]++ @@ -151,11 +179,34 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op page.buildComponents(doc, ctx, &opt) data := Data{"$props": page.Attrs} data.ReplaceSelectionUse(slotRe, first) + + // Add the translation marks + sequence := 0 + err = page.TranslateMarks(ctx, doc, &sequence) + if err != nil { + return "", err + } + + // Translate the scripts + if (scripts != nil) && len(scripts) > 0 { + for _, script := range scripts { + if script.Source == "" { + continue + } + trans, _, err := page.translateScript(script.Source, &sequence) + if err != nil { + return "", err + } + ctx.translations = append(ctx.translations, trans...) + } + } + html, err = body.Html() if err != nil { return "", err } sel.ReplaceWithHtml(html) + ctx.components[page.Route] = true return html, nil } @@ -496,3 +547,162 @@ func addTabToEachLine(input string, prefix ...string) string { return strings.Join(lines, "\n") } + +// TranslateMarks add the translation marks to the document +func (page *Page) TranslateMarks(ctx *BuildContext, doc *goquery.Document, sequence *int) error { + + if doc.Length() == 0 { + return nil + } + + if ctx == nil { + ctx = NewBuildContext(nil) + } + + if ctx.translations == nil { + ctx.translations = []Translation{} + } + + root := doc.First() + translations, err := page.translateNode(root.Nodes[0], sequence) + if err != nil { + return err + } + + if translations != nil { + ctx.translations = append(ctx.translations, translations...) + } + return nil +} + +func (page *Page) translateNode(node *html.Node, sequence *int) ([]Translation, error) { + + translations := []Translation{} + *sequence = *sequence + 1 + + switch node.Type { + case html.DocumentNode: + for child := node.FirstChild; child != nil; child = child.NextSibling { + trans, err := page.translateNode(child, sequence) + if err != nil { + return nil, err + } + translations = append(translations, trans...) + } + break + + case html.ElementNode: + + // Script + if node.Data == "script" { + code := goquery.NewDocumentFromNode(node).Text() + trans, _, err := page.translateScript(code, sequence) + if err != nil { + return nil, err + } + translations = append(translations, trans...) + break + } + + sel := goquery.NewDocumentFromNode(node) + for _, attr := range node.Attr { + + trans, keys, err := page.translateText(attr.Val, sequence, "attr") + if err != nil { + return nil, err + } + if len(keys) > 0 { + raw := strings.Join(keys, ",") + sel.SetAttr("s:trans-attr-"+attr.Key, raw) + translations = append(translations, trans...) + } + + } + + // Node Attributes + for child := node.FirstChild; child != nil; child = child.NextSibling { + trans, err := page.translateNode(child, sequence) + if err != nil { + return nil, err + } + translations = append(translations, trans...) + } + break + + case html.TextNode: + parentSel := goquery.NewDocumentFromNode(node.Parent) + if _, has := parentSel.Attr("s:trans"); has { + key := TranslationKey(page.Route, *sequence) + message := strings.TrimSpace(node.Data) + if message != "" { + translations = append(translations, Translation{ + Key: key, + Message: message, + Type: "text", + }) + parentSel.SetAttr("s:trans-node", key) + *sequence = *sequence + 1 + } + parentSel.RemoveAttr("s:trans") + } + + trans, keys, err := page.translateText(node.Data, sequence, "text") + if err != nil { + return nil, err + } + if len(keys) > 0 { + raw := strings.Join(keys, ",") + parentSel.SetAttr("s:trans-text", raw) + parentSel.RemoveAttr("s:trans") + translations = append(translations, trans...) + } + break + } + + return translations, nil +} + +func (page *Page) translateText(text string, sequence *int, transType string) ([]Translation, []string, error) { + translations := []Translation{} + matches := stmtRe.FindAllStringSubmatch(text, -1) + keys := []string{} + for _, match := range matches { + text := strings.TrimSpace(match[1]) + transMatches := transStmtReSingle.FindAllStringSubmatch(text, -1) + if len(transMatches) == 0 { + transMatches = transStmtReDouble.FindAllStringSubmatch(text, -1) + } + for _, transMatch := range transMatches { + message := strings.TrimSpace(transMatch[1]) + key := TranslationKey(page.Route, *sequence) + keys = append(keys, key) + translations = append(translations, Translation{ + Key: key, + Message: message, + Type: transType, + }) + *sequence = *sequence + 1 + } + } + return translations, keys, nil +} + +func (page *Page) translateScript(code string, sequence *int) ([]Translation, []string, error) { + + translations := []Translation{} + keys := []string{} + if code == "" { + return translations, keys, nil + } + matches := transFuncRe.FindAllStringSubmatch(code, -1) + for _, match := range matches { + key := TranslationKey(page.Route, *sequence) + translations = append(translations, Translation{ + Key: key, + Message: match[1], + Type: "script", + }) + *sequence = *sequence + 1 + } + return translations, keys, nil +} diff --git a/sui/core/compile.go b/sui/core/compile.go index 0dbfe851..27cd6735 100644 --- a/sui/core/compile.go +++ b/sui/core/compile.go @@ -5,20 +5,15 @@ import ( "regexp" "strings" - "github.com/PuerkitoBio/goquery" "github.com/evanw/esbuild/pkg/api" jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou/runtime/transform" "github.com/yaoapp/kun/log" - "golang.org/x/net/html" ) var quoteRe = "'\"`" var importRe = regexp.MustCompile(`import\s*\t*\n*[^;]*;`) // import { foo, bar } from 'hello'; ... var importAssetsRe = regexp.MustCompile(`import\s*\t*\n*\s*['"]@assets\/([^'"]+)['"];`) // import '@assets/foo.js'; or import "@assets/foo.js"; -var transStmtReSingle = regexp.MustCompile(`'::([^:']+)'`) -var transStmtReDouble = regexp.MustCompile(`"::([^:"]+)"`) -var transFuncRe = regexp.MustCompile(`__m\s*\(\s*["'](.*?)["']\s*\)`) // AssetsRe is the regexp for assets var AssetsRe = regexp.MustCompile(`[` + quoteRe + `]@assets\/([^` + quoteRe + `]+)[` + quoteRe + `]`) // '@assets/foo.js' or "@assets/foo.js" or `@assets/foo` @@ -90,12 +85,15 @@ func (page *Page) Compile(ctx *BuildContext, option *BuildOption) (string, []str ) } - // Add the translation marks - sequence := 0 - err = page.TranslateMarks(ctx, option, doc, &sequence) - if err != nil { - return "", warnings, err + // Page Components + components := []string{} + if ctx != nil && ctx.components != nil && len(ctx.components) > 0 { + for route := range ctx.components { + components = append(components, route) + } } + rawComponents, _ := jsoniter.MarshalToString(components) + body.AppendHtml("\n\n" + `\n\n") page.ReplaceDocument(doc) html, err := doc.Html() @@ -140,6 +138,15 @@ func (page *Page) CompileAsComponent(ctx *BuildContext, option *BuildOption) (st return "", warnings, err } + // Page Components + components := []string{} + if ctx != nil && ctx.components != nil && len(ctx.components) > 0 { + for route := range ctx.components { + components = append(components, route) + } + } + rawComponents, _ := jsoniter.MarshalToString(components) + if body.Children().Length() == 0 { return "", warnings, fmt.Errorf("page %s as component should have one root element", page.Route) } @@ -151,13 +158,7 @@ func (page *Page) CompileAsComponent(ctx *BuildContext, option *BuildOption) (st body.Children().First().AppendHtml(fmt.Sprintf(``+"\n", rawScripts)) body.Children().First().AppendHtml(fmt.Sprintf(``+"\n", rawStyles)) body.Children().First().AppendHtml(fmt.Sprintf(``+"\n", rawOption)) - - // Add the translation marks - sequence := 0 - err = page.TranslateMarks(ctx, option, doc, &sequence) - if err != nil { - return "", warnings, err - } + body.Children().First().AppendHtml(fmt.Sprintf(``+"\n", rawComponents)) html, err := body.Html() return html, warnings, err @@ -282,150 +283,3 @@ func (style StyleNode) HTML() string { return "" } - -// TranslateMarks add the translation marks to the document -func (page *Page) TranslateMarks(ctx *BuildContext, option *BuildOption, doc *goquery.Document, sequence *int) error { - - if doc.Length() == 0 { - return nil - } - - if ctx == nil { - ctx = NewBuildContext(nil) - } - - if ctx.translations == nil { - ctx.translations = []Translation{} - } - - root := doc.First() - translations, err := page.translateNode(root.Nodes[0], sequence) - if err != nil { - return err - } - - if translations != nil { - ctx.translations = append(ctx.translations, translations...) - } - return nil -} - -func (page *Page) translateNode(node *html.Node, sequence *int) ([]Translation, error) { - - translations := []Translation{} - *sequence = *sequence + 1 - - switch node.Type { - case html.DocumentNode: - for child := node.FirstChild; child != nil; child = child.NextSibling { - trans, err := page.translateNode(child, sequence) - if err != nil { - return nil, err - } - translations = append(translations, trans...) - } - break - - case html.ElementNode: - - // Script - if node.Data == "script" { - code := goquery.NewDocumentFromNode(node).Text() - if code != "" { - translations := []Translation{} - matches := transFuncRe.FindAllStringSubmatch(code, -1) - for _, match := range matches { - key := Namespace(page.Route, *sequence) - translations = append(translations, Translation{ - Key: key, - Message: match[1], - Type: "script", - }) - *sequence = *sequence + 1 - } - } - break - } - - sel := goquery.NewDocumentFromNode(node) - for _, attr := range node.Attr { - - trans, keys, err := page.translateText(attr.Val, sequence, "attr") - if err != nil { - return nil, err - } - if len(keys) > 0 { - raw := strings.Join(keys, ",") - sel.SetAttr("s:trans-attr-"+attr.Key, raw) - translations = append(translations, trans...) - } - - } - - // Node Attributes - for child := node.FirstChild; child != nil; child = child.NextSibling { - trans, err := page.translateNode(child, sequence) - if err != nil { - return nil, err - } - translations = append(translations, trans...) - } - break - - case html.TextNode: - parentSel := goquery.NewDocumentFromNode(node.Parent) - if _, has := parentSel.Attr("s:trans"); has { - key := Namespace(page.Route, *sequence) - message := strings.TrimSpace(node.Data) - if message != "" { - translations = append(translations, Translation{ - Key: key, - Message: message, - Type: "text", - }) - parentSel.SetAttr("s:trans-node", key) - *sequence = *sequence + 1 - } - parentSel.RemoveAttr("s:trans") - } - - trans, keys, err := page.translateText(node.Data, sequence, "text") - if err != nil { - return nil, err - } - if len(keys) > 0 { - raw := strings.Join(keys, ",") - parentSel.SetAttr("s:trans-text", raw) - parentSel.RemoveAttr("s:trans") - translations = append(translations, trans...) - } - break - } - - return translations, nil -} - -func (page *Page) translateText(text string, sequence *int, typ string) ([]Translation, []string, error) { - translations := []Translation{} - matches := stmtRe.FindAllStringSubmatch(text, -1) - keys := []string{} - for _, match := range matches { - text := strings.TrimSpace(match[1]) - transMatches := transStmtReSingle.FindAllStringSubmatch(text, -1) - if len(transMatches) == 0 { - transMatches = transStmtReDouble.FindAllStringSubmatch(text, -1) - } - for _, transMatch := range transMatches { - message := strings.TrimSpace(transMatch[1]) - key := Namespace(page.Route, *sequence) - keys = append(keys, key) - translations = append(translations, Translation{ - Key: key, - Message: message, - Type: typ, - }) - *sequence = *sequence + 1 - } - } - return translations, keys, nil -} diff --git a/sui/core/context.go b/sui/core/context.go index 2c3be60e..e22bf783 100644 --- a/sui/core/context.go +++ b/sui/core/context.go @@ -3,7 +3,7 @@ package core // NewBuildContext create a new build context func NewBuildContext(global *GlobalBuildContext) *BuildContext { return &BuildContext{ - components: map[string]string{}, + components: map[string]bool{}, sequence: 1, scripts: []ScriptNode{}, scriptUnique: map[string]bool{}, diff --git a/sui/core/types.go b/sui/core/types.go index 518270d9..c40c3998 100644 --- a/sui/core/types.go +++ b/sui/core/types.go @@ -47,7 +47,7 @@ type Page struct { // BuildContext is the struct for the build context type BuildContext struct { - components map[string]string + components map[string]bool jitComponents map[string]bool sequence int doc *goquery.Document diff --git a/sui/core/utils.go b/sui/core/utils.go index 6353de89..0cb7655f 100644 --- a/sui/core/utils.go +++ b/sui/core/utils.go @@ -55,13 +55,13 @@ func Namespace(name string, idx int, hash ...bool) string { name = strings.ReplaceAll(name, "/", "_") name = strings.ReplaceAll(name, "[", "_") name = strings.ReplaceAll(name, "]", "_") - ns := fmt.Sprintf("__namespace_%s", name) + ns := fmt.Sprintf("page_%s_%d", name, idx) if len(hash) > 0 && hash[0] { h := fnv.New64a() h.Write([]byte(ns)) return fmt.Sprintf("ns_%x", h.Sum64()) } - return fmt.Sprintf("__page_%s_%d", name, idx) + return ns } // ComponentName convert the name to component name @@ -69,7 +69,7 @@ func ComponentName(name string, hash ...bool) string { name = strings.ReplaceAll(name, "/", "_") name = strings.ReplaceAll(name, "[", "_") name = strings.ReplaceAll(name, "]", "_") - cn := fmt.Sprintf("__component_%s", name) + cn := fmt.Sprintf("comp_%s", name) if len(hash) > 0 && hash[0] { h := fnv.New64a() h.Write([]byte(cn)) @@ -77,3 +77,11 @@ func ComponentName(name string, hash ...bool) string { } return cn } + +// TranslationKey convert the name to translation key +func TranslationKey(name string, sequence int) string { + name = strings.ReplaceAll(name, "/", "_") + name = strings.ReplaceAll(name, "[", "_") + name = strings.ReplaceAll(name, "]", "_") + return fmt.Sprintf("trans_%s_%d", name, sequence) +}