diff --git a/.attach_pid1342408 b/.attach_pid1342408 deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.attach_pid1349125 b/.attach_pid1349125 deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.gitignore b/.gitignore index a750869c006aef7a6e3559132d7841e41561ffe2..c9341d3dacd58afcf3c63283887548f2ce82e1b6 100644 --- a/.gitignore +++ b/.gitignore @@ -526,3 +526,4 @@ devenv.local.nix # pre-commit .pre-commit-config.yaml +.attach_pid* diff --git a/README.md b/README.md index f3e24861f40c563a91fb843e9d128f8416142205..02d1f5f1eee7383c82902554086de27d870e9207 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ This repository contains a file called flake.nix. You can install this program u #### Prepare ```bash -bob template prepare --input ./templates/ --output ./output/ +bob template prepare --input ./templates/ --output ./output/ --data-file ./data.yaml ``` This will create files in the `./output/` directory with all parsed templates from `./templates/` directory. @@ -32,13 +32,15 @@ Also, a data YAML. This data YAML is used to generate the final files. This command prepares the title, description, keywords, and other metadata for the templates. Furthermore, it will parse the templates for images, anchors, and text. +If the argument `--data-file` is not set, the data YAML will be written to `./output/data.yaml`. + | Original | Parsed | |-------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------| | `<html lang="en"><head>` | `<html lang="en" data-attributes="lang path:lang"><head>` | | `<title>Bob</title>` | `<title data-attributes="title path:title">Bob</title>` | | `<meta name="description" content="Bob is a html and html fragment builder">` | `<meta name="description" content="Bob is a html and html fragment builder" data-attributes="description path:meta.description">` | -| `<img alt="alt text" title="my title" src="..." ` | `<img alt="alt text" title="my title" src="..." data-attributes="alt path:img.id1003.alt title path:img.id1003.title src path:img.id1003.src">` | -| `<a href="https://gitlab.schukai.com/oss/bob">` | `<a href="https://gitlab.schukai.com/oss/bob" data-attributes="href path:a.id1004.href">` | +| `<img alt="alt text" title="my title" src="..." ` | `<img alt="alt text" title="my title" src="..." data-attributes="alt path:img.id1003.alt title path:img.id1003.title src path:img.id1003.src">` | +| `<a href="https://gitlab.schukai.com/oss/bob">` | `<a href="https://gitlab.schukai.com/oss/bob" data-attributes="href path:a.id1004.href">` | | `<p>Bob is a html and html fragment builder</p>` | `<p><span data-attributes="text path:p.id1005.text">Bob is a html and html fragment builder</span></p>` | diff --git a/application/source/command.go b/application/source/command.go index 7885063826478e8fe629c0eb064f8673e0fd8f51..fdec0b7baf1d9fa3160482dc972da577985379a3 100644 --- a/application/source/command.go +++ b/application/source/command.go @@ -82,6 +82,29 @@ func (d *Definition) PrepareTemplate(s *xflags.Settings[Definition]) { storage := types.NewPageDataStorage() + i := d.GetDataFile() + // unmarshal data file yaml to page data storage + if _, err := os.Stat(i); err == nil { + data, err := os.ReadFile(i) + if err != nil { + s.AddError(err) + } else { + err = yaml.Unmarshal(data, storage) + if err != nil { + s.AddError(err) + } + } + + if d.Verbose { + fmt.Printf("Loaded data file %s\n", i) + } + } + + toDelete := []string{} + for page, _ := range storage { + toDelete = append(toDelete, page) + } + err := filepath.Walk(d.Template.Prepare.Input, func(path string, info os.FileInfo, err error) error { if err != nil { @@ -97,9 +120,34 @@ func (d *Definition) PrepareTemplate(s *xflags.Settings[Definition]) { return nil } - return template2.PrepareHtmlFile(path, d.Template.Prepare.Output, storage) + if d.Verbose { + fmt.Printf("Prepare %s\n", path) + } + + key, err := template2.PrepareHtmlFile(path, d.Template.Prepare.Output, storage) + if err != nil { + return err + } + + for i, v := range toDelete { + if v == key { + toDelete = append(toDelete[:i], toDelete[i+1:]...) + break + } + } + + return nil }) + for _, v := range toDelete { + + if d.Verbose { + fmt.Printf("Delete %s\n", v) + } + + delete(storage, v) + } + if err != nil { s.AddError(err) } @@ -109,22 +157,31 @@ func (d *Definition) PrepareTemplate(s *xflags.Settings[Definition]) { s.AddError(err) } else { - o := d.Template.Prepare.DataFile - if o == "" { - o = "data.yaml" - } - - if !path.IsAbs(o) { - o = path.Join(d.Template.Prepare.Output, o) - } + o := d.GetDataFile() err = os.WriteFile(o, data, os.ModePerm) if err != nil { s.AddError(err) } + if d.Verbose { + fmt.Printf("Saved data file %s\n", o) + } + + } + +} + +func (d *Definition) GetDataFile() string { + o := d.Template.Prepare.DataFile + if o == "" { + o = "data.yaml" } + if !path.IsAbs(o) { + o = path.Join(d.Template.Prepare.Output, o) + } + return o } func (d *Definition) PrintHelp(s *xflags.Settings[Definition]) { diff --git a/application/source/html/generate.go b/application/source/html/generate.go index 016b8fe7f823fd93e342d9c8830b63e1c5f796d1..185c10b953b9fee669601b1e2793e6a88b447e91 100644 --- a/application/source/html/generate.go +++ b/application/source/html/generate.go @@ -28,7 +28,7 @@ func GenerateFiles(dataPath, out string) error { for name, page := range storage { p := path.Join(dir, name) - html, err := Generate(page, p) + generatedHtml, err := Generate(page, p) if err != nil { return err } @@ -40,7 +40,7 @@ func GenerateFiles(dataPath, out string) error { return err } - err = os.WriteFile(outFile, []byte(html), 0644) + err = os.WriteFile(outFile, []byte(generatedHtml), 0644) if err != nil { return err } diff --git a/application/source/html/sync.go b/application/source/html/sync.go index 2b36272fc336c1ad9394ad7a65163c7d7a0003a2..1784580f4d8cd019e1b1f9bfd7a339270cfe210b 100644 --- a/application/source/html/sync.go +++ b/application/source/html/sync.go @@ -9,7 +9,6 @@ import ( "gopkg.in/yaml.v3" "os" "path/filepath" - "strings" ) type Specification struct { @@ -202,16 +201,6 @@ func SyncHtml(p string) error { } x := cas.MatchAll(destinationFiles[d]) if x == nil { - - builder := &strings.Builder{} - - // Render the HTML to the builder - html.Render(builder, destinationFiles[d]) - - // Print the captured HTML to the console - a := builder.String() - fmt.Println(a) - return fmt.Errorf("could not find selector %s in %s", sel, d) } diff --git a/application/source/template/prepare.go b/application/source/template/prepare.go index 038bf359664b9cfd156b91ca51b44378ea68f024..fb7fd548e0f6a9da93883693ddefdd515de43df8 100644 --- a/application/source/template/prepare.go +++ b/application/source/template/prepare.go @@ -73,7 +73,16 @@ func setDataAttributesAttribute(node *html.Node, name, attribute, instruction st } -func prepateMeta(node *html.Node, attrKey, attrValue string, storage *types.PageData) { +func prepareMeta(node *html.Node, attrKey, attrValue string, storage *types.PageData) { + + if storage.Meta == nil { + storage.Meta = make(map[string]string) + } + + if _, ok := storage.Meta[attrValue]; ok { + return + } + sel, err := cascadia.Parse("meta[" + attrKey + "=" + attrValue + "]") if err != nil { return @@ -115,6 +124,10 @@ func prepareLanguage(node *html.Node, storage *types.PageData) { func prepareTitle(node *html.Node, storage *types.PageData) { + if storage.Title != "" { + return + } + selector, err := cascadia.Parse("title") if err != nil { return @@ -150,6 +163,10 @@ func prepareAnchors(node *html.Node, storage *types.PageData) { return } + copyOfAnchors := make([]types.Anchor, len(storage.Anchors)) + copy(copyOfAnchors, storage.Anchors) + storage.Anchors = []types.Anchor{} + for _, n := range list { title := util.GetAttribute(n.Attr, "title") @@ -175,6 +192,21 @@ func prepareAnchors(node *html.Node, storage *types.PageData) { }) } + + for _, anchor := range copyOfAnchors { + foundIndex := -1 + for index, i := range storage.Images { + if i.Id == anchor.Id { + foundIndex = index + break + } + } + + if foundIndex > -1 { + storage.Anchors[foundIndex] = anchor + } + } + } func prepareImages(node *html.Node, storage *types.PageData) { @@ -189,6 +221,10 @@ func prepareImages(node *html.Node, storage *types.PageData) { return } + copyOfImages := make([]types.Image, len(storage.Images)) + copy(copyOfImages, storage.Images) + storage.Images = []types.Image{} + for _, n := range list { alt := util.GetAttribute(n.Attr, "alt") @@ -215,6 +251,20 @@ func prepareImages(node *html.Node, storage *types.PageData) { } + for _, image := range copyOfImages { + foundIndex := -1 + for index, i := range storage.Images { + if i.Id == image.Id { + foundIndex = index + break + } + } + + if foundIndex > -1 { + storage.Images[foundIndex] = image + } + } + } func prepareTranslationJson(node *html.Node, storage *types.PageData) { @@ -228,6 +278,10 @@ func prepareTranslationJson(node *html.Node, storage *types.PageData) { return } + copyOfTranslations := make([]types.Translations, len(storage.Translations)) + copy(copyOfTranslations, storage.Translations) + storage.Translations = []types.Translations{} + for _, n := range list { id := util.GetAttribute(n.Attr, "id") @@ -258,6 +312,21 @@ func prepareTranslationJson(node *html.Node, storage *types.PageData) { }) } + + for _, translation := range copyOfTranslations { + foundIndex := -1 + for index, t := range storage.Translations { + if t.Id == translation.Id { + foundIndex = index + break + } + } + + if foundIndex > -1 { + storage.Translations[foundIndex] = translation + } + } + } func prepareTextNodes(node *html.Node, storage *types.PageData) { @@ -272,8 +341,26 @@ func prepareTextNodes(node *html.Node, storage *types.PageData) { return } + copyOfTextNodes := make([]types.Text, len(storage.Text)) + copy(copyOfTextNodes, storage.Text) + storage.Text = []types.Text{} + runNodes(body, storage) + for _, text := range copyOfTextNodes { + foundIndex := -1 + for index, t := range storage.Text { + if t.Id == text.Id { + foundIndex = index + break + } + } + + if foundIndex > -1 { + storage.Text[foundIndex] = text + } + } + } func runNodes(n *html.Node, storage *types.PageData) { @@ -340,21 +427,27 @@ func checkNodes(n *html.Node, storage *types.PageData) { } -func PrepareHtmlFile(from, to string, storage types.PageDataStorage) error { +func PrepareHtmlFile(from, to string, storage types.PageDataStorage) (string, error) { node, err := util.LoadHtml(from) if err != nil { - return err + return "", err } + var pd *types.PageData + var ok bool + p := path.Base(from) - pd := types.NewPageData() - storage[p] = pd + + if pd, ok = storage[p]; !ok { + pd = types.NewPageData() + storage[p] = pd + } prepareLanguage(node, pd) prepareTitle(node, pd) - prepateMeta(node, "name", "description", pd) - prepateMeta(node, "name", "keywords", pd) - prepateMeta(node, "name", "author", pd) + prepareMeta(node, "name", "description", pd) + prepareMeta(node, "name", "keywords", pd) + prepareMeta(node, "name", "author", pd) prepareImages(node, pd) prepareAnchors(node, pd) @@ -365,6 +458,6 @@ func PrepareHtmlFile(from, to string, storage types.PageDataStorage) error { pd.Export = path.Join(pd.Lang, path.Base(from)) to = path.Join(to, path.Base(from)) - return util.SaveHtml(to, node) + return p, util.SaveHtml(to, node) } diff --git a/application/source/util/html.go b/application/source/util/html.go index 1c264710278d05f96dd0e17c4f50898c34accc61..26753f2620c1e2df87698b496c5bfac11ecd075d 100644 --- a/application/source/util/html.go +++ b/application/source/util/html.go @@ -4,6 +4,7 @@ import ( "errors" "golang.org/x/net/html" "os" + "path" "strconv" ) @@ -76,11 +77,24 @@ func SaveHtml(p string, node *html.Node) error { _, err = os.Stat(p) if errors.Is(err, os.ErrNotExist) { + var dir = path.Dir(p) + err := os.MkdirAll(dir, os.ModePerm) + if err != nil { + return err + } + f, err = os.Create(p) + if err != nil { + return err + } + } else if err != nil { return err } else { - os.Remove(p) + err := os.Remove(p) + if err != nil { + return err + } f, err = os.Create(p) if err != nil { return err diff --git a/devenv.lock b/devenv.lock index 31f42d2473d3fcb88129523377ffa9f227213fa8..fd801585765d26030f6ff1bc49ccbbad2cc41806 100644 --- a/devenv.lock +++ b/devenv.lock @@ -3,11 +3,11 @@ "devenv": { "locked": { "dir": "src/modules", - "lastModified": 1688925746, - "narHash": "sha256-Lora6gsuAdVeVeGj2nD4joxTu+jZsAwySlxY1XZVq8o=", + "lastModified": 1689667485, + "narHash": "sha256-tLNoMRSPLlW1D4wgNpSIPUUHd6x1GdjAhETLpRTKnfo=", "owner": "cachix", "repo": "devenv", - "rev": "b058455b37d2a1833eb71bebd3d2b2aa58ce70d7", + "rev": "6f8add968bc12bf81d845eb7dc684a0733bb1518", "type": "github" }, "original": { @@ -74,11 +74,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1688925019, - "narHash": "sha256-281HjmJycKt8rZ0/vpYTtJuZrQl6mpGNlUFf8cebmeA=", + "lastModified": 1689631193, + "narHash": "sha256-AGSkBZaiTODQc8eT1rZDrQIjtb8JtFwJ0wVPzArlrnM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2b356dae6208d422236c4cdc48f3bed749f9daea", + "rev": "57695599bdc4f7bfe5d28cfa23f14b3d8bdf8a5f", "type": "github" }, "original": { @@ -115,11 +115,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1688596063, - "narHash": "sha256-9t7RxBiKWHygsqXtiNATTJt4lim/oSYZV3RG8OjDDng=", + "lastModified": 1689668210, + "narHash": "sha256-XAATwDkaUxH958yXLs1lcEOmU6pSEIkatY3qjqk8X0E=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "c8d18ba345730019c3faf412c96a045ade171895", + "rev": "eb433bff05b285258be76513add6f6c57b441775", "type": "github" }, "original": {