Merge pull request #678 from trheyi/main
refactor: Update BuildContext components to use boolean values instea…
This commit is contained in:
commit
181d592d53
5 changed files with 241 additions and 169 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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" + `<script name="imports" type="json">` + "\n" + rawComponents + "\n</script>\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(`<script name="scripts" type="json">%s</script>`+"\n", rawScripts))
|
||||
body.Children().First().AppendHtml(fmt.Sprintf(`<script name="styles" type="json">%s</script>`+"\n", rawStyles))
|
||||
body.Children().First().AppendHtml(fmt.Sprintf(`<script name="option" type="json">%s</script>`+"\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(`<script name="imports" type="json">%s</script>`+"\n", rawComponents))
|
||||
|
||||
html, err := body.Html()
|
||||
return html, warnings, err
|
||||
|
|
@ -282,150 +283,3 @@ func (style StyleNode) HTML() string {
|
|||
return "<style " + strings.Join(attrs, " ") + ">\n" + style.Source + "\n</style>"
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue