panel/cmd/assets.go

215 lines
4.7 KiB
Go

//go:build dev
/*
Package cmd
Copyright © 2024 Shane C. <shane@scaffoe.com>
*/
package cmd
import (
"errors"
"github.com/a-h/templ/parser/v2"
"github.com/evanw/esbuild/pkg/api"
"github.com/kr/pretty"
"github.com/spf13/cobra"
"io"
"io/fs"
"log"
"os"
"path/filepath"
"strings"
)
var ignoredAssetExtensions = []string{
".css",
".js",
".ts",
}
var ignoredDirectories = []string{
"svg",
"dist",
}
var foundIcons []string
// assetsCmd represents the assets command
var assetsCmd = &cobra.Command{
Use: "assets",
Short: "Generates assets needed for webserver",
Run: func(cmd *cobra.Command, args []string) {
err := filepath.Walk("./web/assets", func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
relPath, _ := strings.CutPrefix(path, "web/assets/")
for _, dir := range ignoredDirectories {
if strings.HasPrefix(relPath, dir) {
return filepath.SkipDir
}
}
for _, ext := range ignoredAssetExtensions {
if strings.HasSuffix(info.Name(), ext) {
return nil
}
}
distFolder, _ := strings.CutSuffix(relPath, info.Name())
if err := os.MkdirAll("web/assets/dist/"+distFolder, 0700); err != nil && !errors.Is(err, fs.ErrExist) {
log.Fatalln(err)
}
copyFile(path, filepath.Join("web/assets/dist/"+distFolder, info.Name()))
return nil
})
if err != nil {
log.Fatalln(err)
}
result := api.Build(api.BuildOptions{
Format: api.FormatESModule,
EntryPoints: []string{"./web/assets/js/*.ts", "./web/assets/js/**/*.ts"},
Outdir: "./web/assets/dist/js",
Sourcemap: api.SourceMapLinked,
MinifyWhitespace: true,
MinifyIdentifiers: true,
MinifySyntax: true,
Splitting: true,
Write: true,
TreeShaking: api.TreeShakingTrue,
Bundle: true,
})
if len(result.Errors) != 0 {
pretty.Println(result.Errors)
os.Exit(1)
}
tmplFile, err := parser.Parse("./web/views/auth/register/show.templ")
if err != nil {
log.Fatalln(err)
}
for _, node := range tmplFile.Nodes {
templateNode, ok := node.(parser.HTMLTemplate)
if !ok {
continue
}
for _, htmlTemplChild := range templateNode.Children {
if elExpress, ok := htmlTemplChild.(parser.TemplElementExpression); ok {
for _, htmlNode := range elExpress.Children {
if htmlNodeEl, ok := htmlNode.(parser.Element); ok {
parseHtmlNode(htmlNodeEl)
}
}
}
}
}
err = filepath.Walk("./web/views/", func(path string, info os.FileInfo, err error) error {
if info.IsDir() || filepath.Ext(info.Name()) != ".templ" {
return nil
}
tmplFile, err := parser.Parse(path)
if err != nil {
return err
}
for _, node := range tmplFile.Nodes {
templateNode, ok := node.(parser.HTMLTemplate)
if !ok {
continue
}
for _, htmlTemplChild := range templateNode.Children {
if elExpress, ok := htmlTemplChild.(parser.TemplElementExpression); ok {
for _, htmlNode := range elExpress.Children {
if htmlNodeEl, ok := htmlNode.(parser.Element); ok {
parseHtmlNode(htmlNodeEl)
}
}
}
}
}
return nil
})
for _, icon := range foundIcons {
copyFile(filepath.Join("web/assets/icons", icon+".svg"), filepath.Join("web/assets/dist/svg/", icon+".svg"))
}
},
}
func parseHtmlNode(node parser.Element) {
if node.Children != nil {
for _, nodeChild := range node.Children {
if nodeChildEl, ok := nodeChild.(parser.Element); ok {
parseHtmlNode(nodeChildEl)
}
}
}
if node.Name == "ion-icon" {
for _, attr := range node.Attributes {
if constAttr, ok := attr.(parser.ConstantAttribute); ok {
if constAttr.Name == "name" {
for _, icon := range foundIcons {
if constAttr.Value == icon {
return
}
}
foundIcons = append(foundIcons, constAttr.Value)
}
}
}
}
}
func init() {
generateCmd.AddCommand(assetsCmd)
}
func copyFile(sourcePath, destinationPath string) {
sourcePath = filepath.Clean(sourcePath)
sourceFile, err := os.Open(sourcePath)
if err != nil {
log.Fatalln(err)
}
defer sourceFile.Close()
destinationPath = filepath.Clean(destinationPath)
if _, err := os.Stat(filepath.Dir(destinationPath)); errors.Is(err, fs.ErrNotExist) {
if err := os.MkdirAll(filepath.Dir(destinationPath), 0700); err != nil {
log.Fatalln(err)
}
}
destinationFile, err := os.Create(destinationPath)
if err != nil {
log.Fatalln(err)
}
defer destinationFile.Close()
_, err = io.Copy(destinationFile, sourceFile)
if err != nil {
log.Fatalln(err)
}
if err := sourceFile.Close(); err != nil {
log.Fatalln(err)
}
if err := destinationFile.Close(); err != nil {
log.Fatalln(err)
}
}