package html import ( "github.com/andybalholm/cascadia" "gitlab.schukai.com/oss/bob.git/types" "gitlab.schukai.com/oss/libraries/go/markup/html/engine" "golang.org/x/net/html" "gopkg.in/yaml.v3" "os" "path/filepath" "strings" ) func CutHtml(p string) error { content, err := os.ReadFile(p) if err != nil { return err } currentDir, _ := os.Getwd() os.Chdir(filepath.Dir(p)) defer os.Chdir(currentDir) specification := types.SnippetsSpecification{} if err := yaml.Unmarshal(content, &specification); err != nil { return err } sourceFiles := make(map[string]*html.Node) for _, r := range specification.Snippets { source := r.Source absSource, err := filepath.Abs(source) if err != nil { return err } if sourceFiles[absSource], err = readHTML(absSource); err != nil { return err } } for _, r := range specification.Snippets { source := r.Source destination := r.Destination absSource, err := filepath.Abs(source) if err != nil { return err } sourceNode, ok := sourceFiles[absSource] if !ok { continue } replacedNodes, err := replaceNodes(sourceNode, r.Replacement) if err != nil { return err } err = setAttributes(replacedNodes, r.Attributes) if err != nil { return err } selectors := r.Selector query, err := cascadia.Compile(selectors) if err != nil { return err } snippetNode := query.MatchFirst(replacedNodes) absDestination, err := filepath.Abs(destination) if err != nil { return err } fp, err := os.Create(absDestination) if err != nil { return err } err = html.Render(fp, snippetNode) err2 := fp.Close() if err2 != nil { return err2 } if err != nil { return err } } return nil } func setAttributes(n *html.Node, attributes []types.Attributes) error { for _, a := range attributes { sel, err := cascadia.Compile(a.Selector) if err != nil { return err } for _, h := range sel.MatchAll(n) { removeAttribute(h.Attr, a.Name) h.Attr = append(h.Attr, html.Attribute{Key: a.Name, Val: a.Value}) } } return nil } func removeAttribute(attrs []html.Attribute, key string) []html.Attribute { var result []html.Attribute for _, attr := range attrs { if attr.Key == key { continue } result = append(result, attr) } return result } func replaceNodes(n *html.Node, replacements []types.ContentReplacement) (*html.Node, error) { ret := engine.CloneNode(n) for _, r := range replacements { doc, err := html.Parse(strings.NewReader(r.Content)) if err != nil { return nil, err } nodeList := []html.Node{} sel, err := cascadia.Compile("head") if err != nil { return nil, err } head := sel.MatchAll(doc) for _, h := range head { if h.FirstChild == nil { continue } for c := h.FirstChild; c != nil; c = c.NextSibling { nodeList = append(nodeList, *c) } } sel, err = cascadia.Compile("body") if err != nil { return nil, err } for _, h := range sel.MatchAll(doc) { if h.FirstChild == nil { continue } for c := h.FirstChild; c != nil; c = c.NextSibling { nodeList = append(nodeList, *c) } } sel, err = cascadia.Compile(r.Selector) if err != nil { return nil, err } for _, h := range sel.MatchAll(ret) { for _, node := range nodeList { h.Parent.InsertBefore(engine.CloneNode(&node), h) } h.Parent.RemoveChild(h) } } return ret, nil }