Refactor prop regex patterns and methods in SUI core
This commit is contained in:
parent
af3a8a4ac4
commit
69e0070b0a
3 changed files with 180 additions and 48 deletions
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
|
|
@ -188,12 +189,15 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op
|
|||
|
||||
// Pass the component props
|
||||
first := body.Children().First()
|
||||
page.copyProps(ctx, sel, first, attrs...)
|
||||
// page.copyProps(ctx, sel, first, attrs...)
|
||||
page.parseProps(sel, first, attrs...)
|
||||
page.copySlots(sel, first)
|
||||
page.copyChildren(sel, first)
|
||||
page.buildComponents(doc, ctx, &opt)
|
||||
data := Data{"$props": page.Attrs}
|
||||
data.ReplaceSelectionUse(slotRe, first)
|
||||
page.replaceProps(first)
|
||||
|
||||
// data := Data{"$props": page.Attrs}
|
||||
// data.ReplaceSelectionUse(slotRe, first)
|
||||
|
||||
// Add the translation marks
|
||||
err = page.TranslateDocument(doc)
|
||||
|
|
@ -262,54 +266,145 @@ func (page *Page) copyChildren(from *goquery.Selection, to *goquery.Selection) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (page *Page) copyProps(ctx *BuildContext, from *goquery.Selection, to *goquery.Selection, extra ...html.Attribute) error {
|
||||
func (page *Page) parseProps(from *goquery.Selection, to *goquery.Selection, extra ...html.Attribute) {
|
||||
attrs := from.Get(0).Attr
|
||||
prefix := "s:prop"
|
||||
if page.Attrs == nil {
|
||||
page.Attrs = map[string]string{}
|
||||
if page.props == nil {
|
||||
page.props = map[string]PageProp{}
|
||||
}
|
||||
|
||||
if attrs == nil {
|
||||
attrs = []html.Attribute{}
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
|
||||
if strings.HasPrefix(attr.Key, "s:") || attr.Key == "is" || attr.Key == "parsed" {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(attr.Key, "...$props") {
|
||||
data := Data{"$props": page.parent.Attrs}
|
||||
val, err := data.Exec(fmt.Sprintf("{{ %s }}", attr.Key[3:]))
|
||||
if err != nil {
|
||||
ctx.warnings = append(ctx.warnings, err.Error())
|
||||
setError(to, err)
|
||||
continue
|
||||
}
|
||||
switch value := val.(type) {
|
||||
case map[string]string:
|
||||
for key, value := range value {
|
||||
page.Attrs[key] = value
|
||||
key = fmt.Sprintf("%s:%s", prefix, key)
|
||||
to.SetAttr(key, value)
|
||||
if attr.Key == "...$props" && page.parent != nil {
|
||||
if page.parent.props != nil {
|
||||
for key, prop := range page.parent.props {
|
||||
page.props[key] = prop
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
val := attr.Val
|
||||
if strings.HasPrefix(attr.Key, `...\$props`) {
|
||||
val = fmt.Sprintf("{{ $props.%s }}", attr.Key[9:])
|
||||
if strings.HasPrefix(attr.Key, "...") && page.parent != nil {
|
||||
val := attr.Key[3:]
|
||||
key := fmt.Sprintf("s:prop:%s", attr.Key)
|
||||
to.SetAttr(key, val)
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(attr.Key, "...") {
|
||||
val = attr.Key[3:]
|
||||
}
|
||||
page.Attrs[attr.Key] = val
|
||||
key := fmt.Sprintf("%s:%s", prefix, attr.Key)
|
||||
to.SetAttr(key, val)
|
||||
trans := from.AttrOr(fmt.Sprintf("s:trans-attr-%s", attr.Key), "")
|
||||
exp := stmtRe.Match([]byte(attr.Val))
|
||||
prop := PageProp{Key: attr.Key, Val: attr.Val, Trans: trans, Exp: exp}
|
||||
page.props[attr.Key] = prop
|
||||
}
|
||||
|
||||
if len(extra) > 0 {
|
||||
if extra != nil && len(extra) > 0 {
|
||||
for _, attr := range extra {
|
||||
attrs = append(attrs, attr)
|
||||
to.SetAttr(attr.Key, attr.Val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (page *Page) replaceProps(sel *goquery.Selection) error {
|
||||
if page.props == nil || len(page.props) == 0 {
|
||||
return nil
|
||||
}
|
||||
data := Data{}
|
||||
for key, prop := range page.props {
|
||||
data[key] = prop.Val
|
||||
}
|
||||
data["$props"] = data
|
||||
return page.replacePropsNode(data, sel.Nodes[0])
|
||||
}
|
||||
|
||||
func (page *Page) replacePropsText(text string, data Data) (string, []string) {
|
||||
trans := []string{}
|
||||
matched := PropFindAllStringSubmatch(text)
|
||||
for _, match := range matched {
|
||||
stmt := match[1]
|
||||
val, err := data.ExecString(stmt)
|
||||
if err != nil {
|
||||
log.Error("[replaceProps] Replace %s: %s", stmt, err)
|
||||
continue
|
||||
}
|
||||
|
||||
text = strings.ReplaceAll(text, match[0], val)
|
||||
vars := PropGetVarNames(stmt)
|
||||
for _, v := range vars {
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if prop, has := page.props[v]; has {
|
||||
if prop.Trans == "" {
|
||||
continue
|
||||
}
|
||||
trans = append(trans, prop.Trans)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return text, trans
|
||||
}
|
||||
|
||||
func (page *Page) replacePropsNode(data Data, node *html.Node) error {
|
||||
switch node.Type {
|
||||
case html.TextNode:
|
||||
text := node.Data
|
||||
if strings.TrimSpace(text) == "" {
|
||||
break
|
||||
}
|
||||
|
||||
text, trans := page.replacePropsText(text, data)
|
||||
if len(trans) > 0 && node.Parent != nil {
|
||||
node.Parent.Attr = append(node.Parent.Attr, html.Attribute{
|
||||
Key: "s:trans-text",
|
||||
Val: strings.Join(trans, ","),
|
||||
})
|
||||
}
|
||||
|
||||
node.Data = text
|
||||
break
|
||||
|
||||
case html.ElementNode:
|
||||
|
||||
// Attrs
|
||||
attrs := []html.Attribute{}
|
||||
for i, attr := range node.Attr {
|
||||
|
||||
if (strings.HasPrefix(attr.Key, "s:") || attr.Key == "is") && !allowUsePropAttrs[attr.Key] {
|
||||
continue
|
||||
}
|
||||
|
||||
val, trans := page.replacePropsText(attr.Val, data)
|
||||
node.Attr[i] = html.Attribute{Key: attr.Key, Val: val}
|
||||
if len(trans) > 0 {
|
||||
key := fmt.Sprintf("s:trans-attr-%s", attr.Key)
|
||||
attrs = append(attrs, html.Attribute{Key: key, Val: strings.Join(trans, ",")})
|
||||
}
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
node.Attr = append(node.Attr, attr)
|
||||
}
|
||||
|
||||
// Children
|
||||
for c := node.FirstChild; c != nil; c = c.NextSibling {
|
||||
err := page.replacePropsNode(data, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@ import (
|
|||
|
||||
// If set the map value, should keep the space at the end of the statement
|
||||
var stmtRe = regexp.MustCompile(`\{\{([\s\S]*?)\}\}`)
|
||||
var propRe = regexp.MustCompile(`\[\{([\s\S]*?)\}\]`)
|
||||
var propRe = regexp.MustCompile(`\[\{([\s\S]*?)\}\]`) // [{ xxx }] will be deprecated
|
||||
var propNewRe = regexp.MustCompile(`\{%([\s\S]*)?%\}`) // {% xxx %}
|
||||
var propVarNameRe = regexp.MustCompile(`(?:\$props\.)?(?:$begin:math:display$'([^']+)'$end:math:display$|(\w+))`)
|
||||
|
||||
// Data data for the template
|
||||
type Data map[string]interface{}
|
||||
|
|
@ -184,3 +186,29 @@ func _process(args ...any) (interface{}, error) {
|
|||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// PropFindAllStringSubmatch find all string submatch
|
||||
func PropFindAllStringSubmatch(value string) [][]string {
|
||||
matched := propNewRe.FindAllStringSubmatch(value, -1)
|
||||
oldVersion := propRe.FindAllStringSubmatch(value, -1) // will be deprecated
|
||||
if len(oldVersion) > 0 {
|
||||
matched = append(matched, oldVersion...)
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
||||
// PropGetVarNames get the variable names
|
||||
func PropGetVarNames(value string) []string {
|
||||
matched := propVarNameRe.FindAllStringSubmatch(value, -1)
|
||||
varNames := []string{}
|
||||
for _, m := range matched {
|
||||
m1 := strings.TrimSpace(m[1])
|
||||
m2 := strings.TrimSpace(m[2])
|
||||
if m1 != "" {
|
||||
varNames = append(varNames, m1)
|
||||
} else {
|
||||
varNames = append(varNames, m2)
|
||||
}
|
||||
}
|
||||
return varNames
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,22 +29,31 @@ type Setting struct {
|
|||
|
||||
// Page is the struct for the page
|
||||
type Page struct {
|
||||
Route string `json:"route"`
|
||||
Name string `json:"name,omitempty"`
|
||||
CacheStore string `json:"-"`
|
||||
TemplateID string `json:"-"`
|
||||
SuiID string `json:"-"`
|
||||
Config *PageConfig `json:"-"`
|
||||
Path string `json:"-"`
|
||||
Root string `json:"-"`
|
||||
Codes SourceCodes `json:"-"`
|
||||
Document []byte `json:"-"`
|
||||
GlobalData []byte `json:"-"`
|
||||
Attrs map[string]string `json:"-"`
|
||||
Attributes []html.Attribute `json:"-"`
|
||||
namespace string `json:"-"`
|
||||
transCtx *TranslateContext `json:"-"`
|
||||
parent *Page `json:"-"`
|
||||
Route string `json:"route"`
|
||||
Name string `json:"name,omitempty"`
|
||||
CacheStore string `json:"-"`
|
||||
TemplateID string `json:"-"`
|
||||
SuiID string `json:"-"`
|
||||
Config *PageConfig `json:"-"`
|
||||
Path string `json:"-"`
|
||||
Root string `json:"-"`
|
||||
Codes SourceCodes `json:"-"`
|
||||
Document []byte `json:"-"`
|
||||
GlobalData []byte `json:"-"`
|
||||
Attrs map[string]string `json:"-"`
|
||||
Attributes []html.Attribute `json:"-"`
|
||||
namespace string `json:"-"`
|
||||
transCtx *TranslateContext `json:"-"`
|
||||
parent *Page `json:"-"`
|
||||
props map[string]PageProp `json:"-"`
|
||||
}
|
||||
|
||||
// PageProp is the struct for the page prop
|
||||
type PageProp struct {
|
||||
Key string `json:"key"`
|
||||
Val string `json:"val"`
|
||||
Exp bool `json:"exp"`
|
||||
Trans string `json:"trans"`
|
||||
}
|
||||
|
||||
// BuildContext is the struct for the build context
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue