package html import ( "encoding/json" "github.com/andybalholm/cascadia" "gitlab.schukai.com/oss/bob/types" "gitlab.schukai.com/oss/libraries/go/markup/html/engine" "golang.org/x/net/html" "gopkg.in/yaml.v3" "os" "path" "strings" ) func GenerateFiles(dataPath, out string) error { dir := path.Dir(dataPath) yamlFile, err := os.ReadFile(dataPath) if err != nil { return err } storage := types.NewPageDataStorage() if err := yaml.Unmarshal(yamlFile, storage); err != nil { return err } for name, page := range storage { p := path.Join(dir, name) html, err := Generate(page, p) if err != nil { return err } outFile := path.Join(out, page.Export) dir := path.Dir(outFile) if err := os.MkdirAll(dir, 0755); err != nil { return err } err = os.WriteFile(outFile, []byte(html), 0644) if err != nil { return err } } return nil } func Generate(data *types.PageData, name string) (string, error) { dataset := make(map[any]any) dataset["lang"] = data.Lang dataset["title"] = data.Title dataset["meta"] = make(map[any]any) for k, v := range data.Meta { dataset["meta"].(map[any]any)[k] = v } dataset["images"] = make(map[any]any, 0) for _, v := range data.Images { dataset["images"].(map[any]any)[v.Id] = map[any]any{ "source": v.Source, "alt": v.Alt, "title": v.Title, "id": v.Id, } } dataset["anchors"] = make(map[any]any, 0) for _, v := range data.Anchors { dataset["anchors"].(map[any]any)[v.Id] = map[any]any{ "href": v.Href, "hreflang": v.HrefLang, "title": v.Title, "id": v.Id, } } dataset["text"] = make(map[any]any, 0) for _, v := range data.Text { dataset["text"].(map[any]any)[v.Id] = map[any]any{"text": v.Text} } dataset["translations"] = make(map[string]any, 0) for _, v := range data.Translations { j, err := json.Marshal(v.KeyValues) if err != nil { return "", err } dataset["translations"].(map[string]any)[v.Id] = map[string]string{ "content": string(j), } } e := engine.New(dataset) template, err := os.ReadFile(name) if err != nil { return "", err } stringWriter := &strings.Builder{} e.ProcessHtml(stringWriter, strings.NewReader(string(template))) return doModifications(data, stringWriter.String()) } func doModifications(page *types.PageData, from string) (string, error) { node, err := html.Parse(strings.NewReader(from)) if err != nil { return "", err } for _, m := range page.Modifications.Remove { selector, err := cascadia.Parse(m) if err != nil { return "", err } list := cascadia.QueryAll(node, selector) for _, n := range list { if n.Parent != nil { n.Parent.RemoveChild(n) } } } for _, m := range page.Modifications.Add { selector, err := cascadia.Parse(m.Selector) if err != nil { return "", err } list := cascadia.QueryAll(node, selector) for _, n := range list { if n.Parent != nil { nodes, err := html.ParseFragment(strings.NewReader(m.Html), n) if err != nil { return "", err } for _, added := range nodes { n.InsertBefore(added, n.FirstChild) } } } } for _, m := range page.Modifications.SetAttribute { selector, err := cascadia.Parse(m.Selector) if err != nil { return "", err } list := cascadia.QueryAll(node, selector) for _, n := range list { if n.Parent != nil { removeAttr(n, m.Name) attr := n.Attr attr = append(attr, html.Attribute{ Key: m.Name, Val: m.Value, }) n.Attr = attr } } } stringWriter := &strings.Builder{} err = html.Render(stringWriter, node) if err != nil { return "", err } return stringWriter.String(), nil } func removeAttr(n *html.Node, search string) { i := -1 for index, attr := range n.Attr { if attr.Key == search { i = index break } } if i != -1 { n.Attr = append(n.Attr[:i], n.Attr[i+1:]...) } }