package javascript import ( "github.com/charmbracelet/log" "golang.org/x/net/html" "os" "path" "strings" "github.com/evanw/esbuild/pkg/api" ) func ParseHTMLFile(p string, development bool) error { data, err := os.ReadFile(p) if err != nil { return err } doc, err := html.Parse(strings.NewReader(string(data))) if err != nil { return err } var f func(*html.Node) f = func(n *html.Node) { var src, source, scriptDist, styleDist, target string if n.Type == html.ElementNode && n.Data == "script" { for _, attr := range n.Attr { if attr.Key == "data-bob-source" { source = attr.Val } else if attr.Key == "data-bob-script-dist" { scriptDist = attr.Val } else if attr.Key == "data-bob-style-dist" { styleDist = attr.Val } else if attr.Key == "data-bob-target" { target = attr.Val } else if attr.Key == "src" { src = attr.Val } } if src != "" { if !path.IsAbs(source) { source = path.Dir(p) + "/" + source if _, err := os.Stat(source); os.IsNotExist(err) { log.Error("File does not exist: " + source) return } } if !path.IsAbs(scriptDist) { scriptDist = path.Dir(p) + "/" + scriptDist } if !path.IsAbs(styleDist) { styleDist = path.Dir(p) + "/" + styleDist } log.Info("Script: " + src + " " + source + " " + scriptDist + " " + styleDist) runESBuild(source, path.Dir(p), scriptDist, styleDist, development, target) } } for c := n.FirstChild; c != nil; c = c.NextSibling { f(c) } } f(doc) return nil } func runESBuild(source, dist, scriptDist, styleDist string, development bool, target string) { // get temporary directory //tempDir, err := os.MkdirTemp("", "build-bob") //if err != nil { // fmt.Println("Fehler beim Erstellen des temporären Verzeichnisses:", err) // return //} // //defer func() { // err := os.RemoveAll(tempDir) // if err != nil { // fmt.Println("Fehler beim Löschen des temporären Verzeichnisses:", err) // } // //}() var treeShaking = api.TreeShakingTrue if development { treeShaking = api.TreeShakingFalse } keepNames := development esbuildTarget := api.ESNext if target != "" { switch { case target == "es5" || target == "es2015": esbuildTarget = api.ES5 keepNames = false case target == "es6" || target == "es2016": esbuildTarget = api.ES2016 case target == "es7" || target == "es2017": esbuildTarget = api.ES2017 case target == "es8" || target == "es2018": esbuildTarget = api.ES2018 case target == "es9" || target == "es2019": esbuildTarget = api.ES2019 case target == "es10" || target == "es2020": esbuildTarget = api.ES2020 case target == "es11" || target == "es2021": esbuildTarget = api.ES2021 case target == "es12" || target == "es2022": esbuildTarget = api.ES2022 case target == "es13" || target == "es2023": esbuildTarget = api.ES2023 case target == "es14" || target == "es2024": esbuildTarget = api.ES2024 default: log.Error("Unknown target: " + target + ". Using ESNext") } } footer := map[string]string{ "js": ` /* * Copyright protects this code. Use, reproduction, or * modification of this code without prior written permission from the copyright holder * is strictly prohibited. For inquiries regarding licenses or usage rights, * please contact schukai GmbH. */`, "css": ` /* * Copyright protects this code. Use, reproduction, or * modification of this code without prior written permission from the copyright holder * is strictly prohibited. For inquiries regarding licenses or usage rights, * please contact schukai GmbH. */ `, } var sourceMap = api.SourceMapNone if development { sourceMap = api.SourceMapInline } result := api.Build(api.BuildOptions{ EntryPoints: []string{source}, Outfile: path.Join(path.Base(scriptDist)), Bundle: true, Write: false, LogLevel: api.LogLevelInfo, Target: esbuildTarget, MinifySyntax: !development, MinifyWhitespace: !development, MinifyIdentifiers: !development, TreeShaking: treeShaking, KeepNames: keepNames, Sourcemap: sourceMap, LegalComments: api.LegalCommentsExternal, Footer: footer, }) if len(result.Errors) > 0 { for _, err := range result.Errors { log.Error(err.Text) } } for _, warning := range result.Warnings { log.Warn(warning.Text) } for _, file := range result.OutputFiles { switch path.Ext(file.Path) { case ".mjs": err := os.WriteFile(scriptDist, file.Contents, os.ModePerm) if err != nil { log.Error(err.Error()) } else { log.Info("Saved " + scriptDist) } case ".js": err := os.WriteFile(scriptDist, file.Contents, os.ModePerm) if err != nil { log.Error(err.Error()) } else { log.Info("Saved " + scriptDist) } case ".css": err := os.WriteFile(styleDist, file.Contents, os.ModePerm) if err != nil { log.Error(err.Error()) } else { log.Info("Saved " + styleDist) } case ".txt": content := file.Contents if strings.TrimSpace(string(content)) == "" { continue } if strings.Contains(file.Path, "LEGAL") { if development { log.Info("Legal information not saved in development mode") continue } if strings.Contains(file.Path, "js") { out := path.Join(path.Dir(scriptDist), path.Base(file.Path)) err := os.WriteFile(out, file.Contents, os.ModePerm) if err != nil { log.Error(err.Error()) } else { log.Info("Saved " + out) } } else { out := path.Join(path.Dir(styleDist), path.Base(file.Path)) err := os.WriteFile(out, file.Contents, os.ModePerm) if err != nil { log.Error(err.Error()) } else { log.Info("Saved " + out) } } } } } }