Merge pull request #541 from trheyi/main
[add] support for importing asset JS files and sui page guard support
This commit is contained in:
commit
5940ddc264
10 changed files with 337 additions and 39 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -81,6 +82,13 @@ func withStaticFileServer(c *gin.Context) {
|
||||||
|
|
||||||
html, code, err := r.Render()
|
html, code, err := r.Render()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if code == 301 || code == 302 {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
c.Redirect(code, err.Error())
|
||||||
|
c.Done()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
log.Error("Sui Render Error: %s", err.Error())
|
log.Error("Sui Render Error: %s", err.Error())
|
||||||
c.AbortWithError(code, err)
|
c.AbortWithError(code, err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
141
sui/api/guards.go
Normal file
141
sui/api/guards.go
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
"github.com/yaoapp/gou/process"
|
||||||
|
"github.com/yaoapp/yao/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Guards middlewares
|
||||||
|
var Guards = map[string]func(c *gin.Context) error{
|
||||||
|
"bearer-jwt": guardBearerJWT, // Bearer JWT
|
||||||
|
"query-jwt": guardQueryJWT, // Get JWT Token from query string "__tk"
|
||||||
|
"cookie-jwt": guardCookieJWT, // Get JWT Token from cookie "__tk"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWT Bearer JWT
|
||||||
|
func guardBearerJWT(c *gin.Context) error {
|
||||||
|
|
||||||
|
tokenString := c.Request.Header.Get("Authorization")
|
||||||
|
tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer "))
|
||||||
|
if tokenString == "" {
|
||||||
|
c.JSON(403, gin.H{"code": 403, "message": "No permission"})
|
||||||
|
c.Abort()
|
||||||
|
return fmt.Errorf("No permission")
|
||||||
|
}
|
||||||
|
|
||||||
|
claims := helper.JwtValidate(tokenString)
|
||||||
|
c.Set("__sid", claims.SID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWT Bearer JWT
|
||||||
|
func guardCookieJWT(c *gin.Context) error {
|
||||||
|
tokenString, err := c.Cookie("__tk")
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(403, gin.H{"code": 403, "message": "No permission"})
|
||||||
|
c.Abort()
|
||||||
|
return fmt.Errorf("No permission")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tokenString == "" {
|
||||||
|
c.JSON(403, gin.H{"code": 403, "message": "No permission"})
|
||||||
|
c.Abort()
|
||||||
|
return fmt.Errorf("No permission")
|
||||||
|
}
|
||||||
|
|
||||||
|
claims := helper.JwtValidate(tokenString)
|
||||||
|
c.Set("__sid", claims.SID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWT Bearer JWT
|
||||||
|
func guardQueryJWT(c *gin.Context) error {
|
||||||
|
tokenString := c.Query("__tk")
|
||||||
|
if tokenString == "" {
|
||||||
|
c.JSON(403, gin.H{"code": 403, "message": "No permission"})
|
||||||
|
c.Abort()
|
||||||
|
return fmt.Errorf("No permission")
|
||||||
|
}
|
||||||
|
|
||||||
|
claims := helper.JwtValidate(tokenString)
|
||||||
|
c.Set("__sid", claims.SID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessGuard guard process
|
||||||
|
func (r *Request) processGuard(name string) error {
|
||||||
|
var body interface{}
|
||||||
|
c := r.context
|
||||||
|
|
||||||
|
if c.Request.Body != nil {
|
||||||
|
|
||||||
|
bodyBytes, err := io.ReadAll(c.Request.Body)
|
||||||
|
if err == nil {
|
||||||
|
if strings.HasPrefix(strings.ToLower(c.Request.Header.Get("Content-Type")), "application/json") {
|
||||||
|
jsoniter.Unmarshal(bodyBytes, &body)
|
||||||
|
} else {
|
||||||
|
body = string(bodyBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset body
|
||||||
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
params := map[string]string{}
|
||||||
|
for _, param := range c.Params {
|
||||||
|
params[param.Key] = param.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []interface{}{
|
||||||
|
r.URL, // page url
|
||||||
|
r.Params, // page params
|
||||||
|
r.Query, // query string
|
||||||
|
r.Payload, // payload
|
||||||
|
r.Headers, // Request headers
|
||||||
|
}
|
||||||
|
|
||||||
|
process, err := process.Of(name, args...)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(403, gin.H{"code": 403, "message": fmt.Sprintf("Guard: %s %s", name, err.Error())})
|
||||||
|
c.Abort()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if sid, has := c.Get("__sid"); has { // 设定会话ID
|
||||||
|
if sid, ok := sid.(string); ok {
|
||||||
|
process.WithSID(sid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if global, has := c.Get("__global"); has { // 设定全局变量
|
||||||
|
if global, ok := global.(map[string]interface{}); ok {
|
||||||
|
process.WithGlobal(global)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := process.Exec()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if data, ok := v.(map[string]interface{}); ok {
|
||||||
|
if sid, ok := data["__sid"].(string); ok {
|
||||||
|
c.Set("__sid", sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
if global, ok := data["__global"].(map[string]interface{}); ok {
|
||||||
|
c.Set("__global", global)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/yaoapp/gou/application"
|
"github.com/yaoapp/gou/application"
|
||||||
|
"github.com/yaoapp/kun/exception"
|
||||||
"github.com/yaoapp/kun/log"
|
"github.com/yaoapp/kun/log"
|
||||||
"github.com/yaoapp/yao/sui/core"
|
"github.com/yaoapp/yao/sui/core"
|
||||||
)
|
)
|
||||||
|
|
@ -17,6 +19,7 @@ import (
|
||||||
type Request struct {
|
type Request struct {
|
||||||
File string
|
File string
|
||||||
*core.Request
|
*core.Request
|
||||||
|
context *gin.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRequestContext is the constructor for Request.
|
// NewRequestContext is the constructor for Request.
|
||||||
|
|
@ -45,7 +48,8 @@ func NewRequestContext(c *gin.Context) (*Request, int, error) {
|
||||||
path := strings.TrimSuffix(c.Request.URL.Path, ".sui")
|
path := strings.TrimSuffix(c.Request.URL.Path, ".sui")
|
||||||
|
|
||||||
return &Request{
|
return &Request{
|
||||||
File: file,
|
File: file,
|
||||||
|
context: c,
|
||||||
Request: &core.Request{
|
Request: &core.Request{
|
||||||
Method: c.Request.Method,
|
Method: c.Request.Method,
|
||||||
Query: c.Request.URL.Query(),
|
Query: c.Request.URL.Query(),
|
||||||
|
|
@ -82,6 +86,21 @@ func (r *Request) Render() (string, int, error) {
|
||||||
return "", 500, err
|
return "", 500, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard := ""
|
||||||
|
configText := ""
|
||||||
|
configSel := doc.Find("script[name=config]")
|
||||||
|
if configSel != nil && configSel.Length() > 0 {
|
||||||
|
configText = configSel.Text()
|
||||||
|
configSel.Remove()
|
||||||
|
|
||||||
|
var conf core.PageConfig
|
||||||
|
err := jsoniter.UnmarshalFromString(configText, &conf)
|
||||||
|
if err != nil {
|
||||||
|
return "", 500, fmt.Errorf("config error, please re-complie the page %s", err.Error())
|
||||||
|
}
|
||||||
|
guard = conf.Guard
|
||||||
|
}
|
||||||
|
|
||||||
dataText := ""
|
dataText := ""
|
||||||
dataSel := doc.Find("script[name=data]")
|
dataSel := doc.Find("script[name=data]")
|
||||||
if dataSel != nil && dataSel.Length() > 0 {
|
if dataSel != nil && dataSel.Length() > 0 {
|
||||||
|
|
@ -107,10 +126,31 @@ func (r *Request) Render() (string, int, error) {
|
||||||
Data: dataText,
|
Data: dataText,
|
||||||
Global: globalDataText,
|
Global: globalDataText,
|
||||||
HTML: html,
|
HTML: html,
|
||||||
|
Guard: guard,
|
||||||
|
Config: configText,
|
||||||
}
|
}
|
||||||
log.Trace("The page %s is cached", r.File)
|
log.Trace("The page %s is cached", r.File)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Guard the page
|
||||||
|
if c.Guard != "" && r.context != nil {
|
||||||
|
|
||||||
|
if guard, has := Guards[c.Guard]; has {
|
||||||
|
err := guard(r.context)
|
||||||
|
if err != nil {
|
||||||
|
ex := exception.Err(err, 403)
|
||||||
|
return "", ex.Code, fmt.Errorf("%s", ex.Message)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Process the guard
|
||||||
|
err := r.processGuard(c.Guard)
|
||||||
|
if err != nil {
|
||||||
|
ex := exception.Err(err, 403)
|
||||||
|
return "", ex.Code, fmt.Errorf("%s", ex.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
data := core.Data{}
|
data := core.Data{}
|
||||||
if c.Data != "" {
|
if c.Data != "" {
|
||||||
|
|
@ -128,6 +168,12 @@ func (r *Request) Render() (string, int, error) {
|
||||||
data["$global"] = global
|
data["$global"] = global
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the page request data
|
||||||
|
data["$payload"] = r.Request.Payload
|
||||||
|
data["$query"] = r.Request.Query
|
||||||
|
data["$param"] = r.Request.Params
|
||||||
|
data["$url"] = r.Request.URL
|
||||||
|
|
||||||
printData := false
|
printData := false
|
||||||
if r.Query != nil && r.Query.Has("__sui_print_data") {
|
if r.Query != nil && r.Query.Has("__sui_print_data") {
|
||||||
printData = true
|
printData = true
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package core
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -43,11 +44,17 @@ func (page *Page) Build(option *BuildOption) (*goquery.Document, []string, error
|
||||||
doc.Selection.Find("head").AppendHtml(style)
|
doc.Selection.Find("head").AppendHtml(style)
|
||||||
|
|
||||||
// Add Script
|
// Add Script
|
||||||
script, err := page.BuildScript(option)
|
code, scripts, err := page.BuildScript(option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
warnings = append(warnings, err.Error())
|
warnings = append(warnings, err.Error())
|
||||||
}
|
}
|
||||||
doc.Selection.Find("body").AppendHtml(script)
|
if scripts != nil {
|
||||||
|
for _, script := range scripts {
|
||||||
|
doc.Selection.Find("body").AppendHtml("\n" + `<script src="` + script + `"></script>` + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doc.Selection.Find("body").AppendHtml(code)
|
||||||
|
|
||||||
return doc, warnings, nil
|
return doc, warnings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,7 +96,7 @@ func (page *Page) BuildForImport(option *BuildOption, slots map[string]interface
|
||||||
warnings = append(warnings, err.Error())
|
warnings = append(warnings, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
script, err := page.BuildScript(option)
|
code, _, err := page.BuildScript(option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
warnings = append(warnings, err.Error())
|
warnings = append(warnings, err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +115,7 @@ func (page *Page) BuildForImport(option *BuildOption, slots map[string]interface
|
||||||
|
|
||||||
// Replace the slots
|
// Replace the slots
|
||||||
html, _ = Data(data).ReplaceUse(slotRe, html)
|
html, _ = Data(data).ReplaceUse(slotRe, html)
|
||||||
return html, style, script, warnings, nil
|
return html, style, code, warnings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (page *Page) parse(doc *goquery.Document, option *BuildOption, warnings []string) error {
|
func (page *Page) parse(doc *goquery.Document, option *BuildOption, warnings []string) error {
|
||||||
|
|
@ -267,8 +274,12 @@ func (page *Page) BuildStyle(option *BuildOption) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
code := page.Codes.CSS.Code
|
code := page.Codes.CSS.Code
|
||||||
|
|
||||||
|
// Replace the assets
|
||||||
if !option.IgnoreAssetRoot {
|
if !option.IgnoreAssetRoot {
|
||||||
code = strings.ReplaceAll(page.Codes.CSS.Code, "@assets", option.AssetRoot)
|
code = AssetsRe.ReplaceAllStringFunc(code, func(match string) string {
|
||||||
|
return strings.ReplaceAll(match, "@assets", option.AssetRoot)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.Namespace != "" {
|
if option.Namespace != "" {
|
||||||
|
|
@ -282,43 +293,65 @@ func (page *Page) BuildStyle(option *BuildOption) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("<style>\n%s\n</style>\n", res), nil
|
return fmt.Sprintf("<style type=\"text/css\">\n%s\n</style>\n", res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildScript build the script
|
// BuildScript build the script
|
||||||
func (page *Page) BuildScript(option *BuildOption) (string, error) {
|
func (page *Page) BuildScript(option *BuildOption) (string, []string, error) {
|
||||||
|
|
||||||
if page.Codes.JS.Code == "" && page.Codes.TS.Code == "" {
|
if page.Codes.JS.Code == "" && page.Codes.TS.Code == "" {
|
||||||
return "", nil
|
return "", nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if page.Codes.TS.Code != "" {
|
if page.Codes.TS.Code != "" {
|
||||||
res, err := page.CompileTS([]byte(page.Codes.TS.Code), false)
|
code, scripts, err := page.CompileTS([]byte(page.Codes.TS.Code), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the assets
|
||||||
|
if !option.IgnoreAssetRoot {
|
||||||
|
code = AssetsRe.ReplaceAllFunc(code, func(match []byte) []byte {
|
||||||
|
return []byte(strings.ReplaceAll(string(match), "@assets", option.AssetRoot))
|
||||||
|
})
|
||||||
|
|
||||||
|
if scripts != nil {
|
||||||
|
for i, script := range scripts {
|
||||||
|
scripts[i] = filepath.Join(option.AssetRoot, script)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.Namespace == "" {
|
if option.Namespace == "" {
|
||||||
return fmt.Sprintf("<script>\n%s\n</script>\n", res), nil
|
return fmt.Sprintf("<script type=\"text/javascript\">\n%s\n</script>\n", code), scripts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("<script>\nfunction %s(){\n%s\n}\n</script>\n", option.Namespace, addTabToEachLine(string(res))), nil
|
return fmt.Sprintf("<script type=\"text/javascript\">\nfunction %s(){\n%s\n}\n</script>\n", option.Namespace, addTabToEachLine(string(code))), scripts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
code := page.Codes.JS.Code
|
code, scripts, err := page.CompileJS([]byte(page.Codes.JS.Code), false)
|
||||||
if !option.IgnoreAssetRoot {
|
|
||||||
code = strings.ReplaceAll(page.Codes.JS.Code, "@assets", option.AssetRoot)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := page.CompileJS([]byte(code), false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the assets
|
||||||
|
if !option.IgnoreAssetRoot {
|
||||||
|
code = AssetsRe.ReplaceAllFunc(code, func(match []byte) []byte {
|
||||||
|
return []byte(strings.ReplaceAll(string(match), "@assets", option.AssetRoot))
|
||||||
|
})
|
||||||
|
|
||||||
|
if scripts != nil {
|
||||||
|
for i, script := range scripts {
|
||||||
|
scripts[i] = filepath.Join(option.AssetRoot, script)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.Namespace == "" {
|
if option.Namespace == "" {
|
||||||
return fmt.Sprintf("<script>\n%s\n</script>\n", res), nil
|
return fmt.Sprintf("<script type=\"text/javascript\">\n%s\n</script>\n", code), scripts, nil
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("<script>\nfunction %s(){\n%s\n}\n</script>\n", option.Namespace, addTabToEachLine(string(res))), nil
|
|
||||||
|
return fmt.Sprintf("<script type=\"text/javascript\">\nfunction %s(){\n%s\n}\n</script>\n", option.Namespace, addTabToEachLine(string(code))), scripts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addTabToEachLine(input string, prefix ...string) string {
|
func addTabToEachLine(input string, prefix ...string) string {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,13 @@ import (
|
||||||
"github.com/yaoapp/kun/log"
|
"github.com/yaoapp/kun/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
// AssetsRe is the regexp for assets
|
||||||
|
var AssetsRe = regexp.MustCompile(`[` + quoteRe + `]@assets\/([^` + quoteRe + `]+)[` + quoteRe + `]`) // '@assets/foo.js' or "@assets/foo.js" or `@assets/foo`
|
||||||
|
|
||||||
// Compile the page
|
// Compile the page
|
||||||
func (page *Page) Compile(option *BuildOption) (string, error) {
|
func (page *Page) Compile(option *BuildOption) (string, error) {
|
||||||
|
|
||||||
|
|
@ -22,6 +29,17 @@ func (page *Page) Compile(option *BuildOption) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Page Config
|
||||||
|
page.Config = page.GetConfig()
|
||||||
|
|
||||||
|
// Config Data
|
||||||
|
if page.Config != nil {
|
||||||
|
doc.Find("body").AppendHtml("\n\n" + `<script name="config" type="json">` + "\n" +
|
||||||
|
page.ExportConfig() +
|
||||||
|
"\n</script>\n\n",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Page Data
|
// Page Data
|
||||||
if page.Codes.DATA.Code != "" {
|
if page.Codes.DATA.Code != "" {
|
||||||
doc.Find("body").AppendHtml("\n\n" + `<script name="data" type="json">` + "\n" +
|
doc.Find("body").AppendHtml("\n\n" + `<script name="data" type="json">` + "\n" +
|
||||||
|
|
@ -38,10 +56,7 @@ func (page *Page) Compile(option *BuildOption) (string, error) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the document
|
|
||||||
page.Config = page.GetConfig()
|
|
||||||
page.ReplaceDocument(doc)
|
page.ReplaceDocument(doc)
|
||||||
|
|
||||||
html, err := doc.Html()
|
html, err := doc.Html()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -52,18 +67,36 @@ func (page *Page) Compile(option *BuildOption) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompileJS compile the javascript
|
// CompileJS compile the javascript
|
||||||
func (page *Page) CompileJS(source []byte, minify bool) ([]byte, error) {
|
func (page *Page) CompileJS(source []byte, minify bool) ([]byte, []string, error) {
|
||||||
jsCode := regexp.MustCompile(`import\s+.*;`).ReplaceAllString(string(source), "")
|
scripts := []string{}
|
||||||
|
matches := importAssetsRe.FindAll(source, -1)
|
||||||
|
for _, match := range matches {
|
||||||
|
assets := AssetsRe.FindStringSubmatch(string(match))
|
||||||
|
if len(assets) > 1 {
|
||||||
|
scripts = append(scripts, assets[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsCode := importRe.ReplaceAllString(string(source), "")
|
||||||
if minify {
|
if minify {
|
||||||
minified, err := transform.MinifyJS(jsCode)
|
minified, err := transform.MinifyJS(jsCode)
|
||||||
return []byte(minified), err
|
return []byte(minified), scripts, err
|
||||||
}
|
}
|
||||||
return []byte(jsCode), nil
|
return []byte(jsCode), scripts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompileTS compile the typescript
|
// CompileTS compile the typescript
|
||||||
func (page *Page) CompileTS(source []byte, minify bool) ([]byte, error) {
|
func (page *Page) CompileTS(source []byte, minify bool) ([]byte, []string, error) {
|
||||||
tsCode := regexp.MustCompile(`import\s+.*;`).ReplaceAllString(string(source), "")
|
|
||||||
|
scripts := []string{}
|
||||||
|
matches := importAssetsRe.FindAll(source, -1)
|
||||||
|
for _, match := range matches {
|
||||||
|
assets := AssetsRe.FindStringSubmatch(string(match))
|
||||||
|
if len(assets) > 1 {
|
||||||
|
scripts = append(scripts, assets[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tsCode := importRe.ReplaceAllString(string(source), "")
|
||||||
if minify {
|
if minify {
|
||||||
jsCode, err := transform.TypeScript(string(tsCode), api.TransformOptions{
|
jsCode, err := transform.TypeScript(string(tsCode), api.TransformOptions{
|
||||||
Target: api.ESNext,
|
Target: api.ESNext,
|
||||||
|
|
@ -71,12 +104,11 @@ func (page *Page) CompileTS(source []byte, minify bool) ([]byte, error) {
|
||||||
MinifyIdentifiers: true,
|
MinifyIdentifiers: true,
|
||||||
MinifySyntax: true,
|
MinifySyntax: true,
|
||||||
})
|
})
|
||||||
|
return []byte(jsCode), scripts, err
|
||||||
return []byte(jsCode), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jsCode, err := transform.TypeScript(string(tsCode), api.TransformOptions{Target: api.ESNext})
|
jsCode, err := transform.TypeScript(string(tsCode), api.TransformOptions{Target: api.ESNext})
|
||||||
return []byte(jsCode), err
|
return []byte(jsCode), scripts, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompileCSS compile the css
|
// CompileCSS compile the css
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var stmtRe = regexp.MustCompile(`\{\{([^}]+)\}\}`)
|
var stmtRe = regexp.MustCompile(`\{\{([^}]+)\}\}`)
|
||||||
|
var propRe = regexp.MustCompile(`\[\{([^}]+)\}\]`)
|
||||||
|
|
||||||
// Data data for the template
|
// Data data for the template
|
||||||
type Data map[string]interface{}
|
type Data map[string]interface{}
|
||||||
|
|
@ -26,8 +27,24 @@ var options = []expr.Option{
|
||||||
|
|
||||||
// New create a new expression
|
// New create a new expression
|
||||||
func (data Data) New(stmt string) (*vm.Program, error) {
|
func (data Data) New(stmt string) (*vm.Program, error) {
|
||||||
stmt = strings.TrimSpace(strings.TrimRight(strings.TrimLeft(stmt, "{{ "), "}}"))
|
|
||||||
stmt = strings.TrimSpace(strings.TrimRight(strings.TrimLeft(stmt, "[{ "), "}]"))
|
stmt = stmtRe.ReplaceAllStringFunc(stmt, func(stmt string) string {
|
||||||
|
matches := stmtRe.FindStringSubmatch(stmt)
|
||||||
|
if len(matches) > 0 {
|
||||||
|
stmt = strings.ReplaceAll(stmt, matches[0], matches[1])
|
||||||
|
}
|
||||||
|
return stmt
|
||||||
|
})
|
||||||
|
|
||||||
|
stmt = propRe.ReplaceAllStringFunc(stmt, func(stmt string) string {
|
||||||
|
matches := propRe.FindStringSubmatch(stmt)
|
||||||
|
if len(matches) > 0 {
|
||||||
|
stmt = strings.ReplaceAll(stmt, matches[0], matches[1])
|
||||||
|
}
|
||||||
|
return stmt
|
||||||
|
})
|
||||||
|
|
||||||
|
stmt = strings.TrimSpace(stmt)
|
||||||
// ' => ' " => "
|
// ' => ' " => "
|
||||||
stmt = strings.ReplaceAll(stmt, "'", "'")
|
stmt = strings.ReplaceAll(stmt, "'", "'")
|
||||||
stmt = strings.ReplaceAll(stmt, """, "\"")
|
stmt = strings.ReplaceAll(stmt, """, "\"")
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ func (page *Page) GetConfig() *PageConfig {
|
||||||
|
|
||||||
if page.Codes.CONF.Code != "" {
|
if page.Codes.CONF.Code != "" {
|
||||||
var config PageConfig
|
var config PageConfig
|
||||||
err := jsoniter.Unmarshal([]byte(page.Codes.CONF.Code), &config)
|
err := jsoniter.UnmarshalFromString(page.Codes.CONF.Code, &config)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
page.Config = &config
|
page.Config = &config
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +57,24 @@ func (page *Page) GetConfig() *PageConfig {
|
||||||
return page.Config
|
return page.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExportConfig export the config
|
||||||
|
func (page *Page) ExportConfig() string {
|
||||||
|
if page.Config == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := jsoniter.MarshalToString(map[string]interface{}{
|
||||||
|
"title": page.Config.Title,
|
||||||
|
"guard": page.Config.Guard,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[sui] export page config error %s", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
// Data get the data (deprecated)
|
// Data get the data (deprecated)
|
||||||
func (page *Page) Data(request *Request) (Data, map[string]interface{}, error) {
|
func (page *Page) Data(request *Request) (Data, map[string]interface{}, error) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import (
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
Data string
|
Data string
|
||||||
Global string
|
Global string
|
||||||
|
Config string
|
||||||
|
Guard string
|
||||||
HTML string
|
HTML string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,7 @@ type PageConfig struct {
|
||||||
// PageSetting is the struct for the page setting
|
// PageSetting is the struct for the page setting
|
||||||
type PageSetting struct {
|
type PageSetting struct {
|
||||||
Title string `json:"title,omitempty"`
|
Title string `json:"title,omitempty"`
|
||||||
|
Guard string `json:"guard,omitempty"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
SEO *PageSEO `json:"seo,omitempty"`
|
SEO *PageSEO `json:"seo,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -629,7 +629,7 @@ func (page *Page) AssetScript() (*core.Asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
jsCode, err := page.CompileTS(tsCode, false)
|
jsCode, _, err := page.CompileTS(tsCode, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -647,7 +647,7 @@ func (page *Page) AssetScript() (*core.Asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
jsCode, err = page.CompileJS(jsCode, false)
|
jsCode, _, err = page.CompileJS(jsCode, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue