From 3ee4d49c34c7a7e22cf573bf5023c87e4c8cf78b Mon Sep 17 00:00:00 2001 From: Anirudh Sudhir Date: Fri, 26 Apr 2024 12:20:16 +0530 Subject: [PATCH 1/3] feat: update documentation and add helper/ tests To be added: note tests --- .gitignore | 4 +- cmd/anna/anna.go | 3 + go.mod | 8 - go.sum | 18 - pkg/engine/anna_engine.go | 2 +- pkg/engine/anna_engine_test.go | 2 +- pkg/helpers/helper.go | 182 +++++----- pkg/helpers/helper_test.go | 68 +++- pkg/parser/parser.go | 15 +- pkg/parser/parser_test.go | 62 ++++ pkg/parser/zettel_parser.go | 2 + site/content/developer-guide.md | 27 ++ site/content/docs-update.md | 6 +- site/content/docs.md | 328 +++++++++--------- site/content/quick-start.md | 62 ++++ site/layout/config.yml | 2 + site/public/public.txt | 1 + test/engine/json_index_test/want_index.json | 2 +- .../input_dir/sub_dir2/sub_sub_dir2/file2.txt | 1 + .../copy_dir/input_dir/sub_dir_1/file1.txt | 1 + test/helpers/copy_files/input.txt | 1 + 21 files changed, 484 insertions(+), 313 deletions(-) create mode 100644 site/content/developer-guide.md create mode 100644 site/content/quick-start.md create mode 100644 site/public/public.txt create mode 100644 test/helpers/copy_dir/input_dir/sub_dir2/sub_sub_dir2/file2.txt create mode 100644 test/helpers/copy_dir/input_dir/sub_dir_1/file1.txt create mode 100644 test/helpers/copy_files/input.txt diff --git a/.gitignore b/.gitignore index 576c567..8518e0e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,9 @@ anna *.exe **/.DS_Store *.prof -ssg/ -*.txt dist/ #Test directories **/rendered/ test/**/static/ -test/**/got_sitemap.xml \ No newline at end of file +test/**/got_sitemap.xml diff --git a/cmd/anna/anna.go b/cmd/anna/anna.go index 0dc12e3..5323d75 100644 --- a/cmd/anna/anna.go +++ b/cmd/anna/anna.go @@ -66,6 +66,9 @@ func (cmd *Cmd) VanillaRender() { // Copies the contents of the 'static/' directory to 'rendered/' helper.CopyDirectoryContents(helpers.SiteDataPath+"static/", helpers.SiteDataPath+"rendered/static/") + // Copies the contents of the 'static/' directory to 'rendered/' + helper.CopyDirectoryContents(helpers.SiteDataPath+"public/", helpers.SiteDataPath+"rendered/") + e.GenerateSitemap(helpers.SiteDataPath + "rendered/sitemap.xml") e.GenerateFeed() e.GenerateJSONIndex(helpers.SiteDataPath) diff --git a/go.mod b/go.mod index 3fbc6bf..8da9c94 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.22.2 require ( github.com/PuerkitoBio/goquery v1.9.1 - github.com/cheggaaa/pb/v3 v3.1.5 github.com/mangoumbrella/goldmark-figure v1.0.0 github.com/spf13/cobra v1.8.0 github.com/yuin/goldmark v1.7.1 @@ -15,18 +14,11 @@ require ( ) require ( - github.com/VividCortex/ewma v1.2.0 // indirect github.com/andybalholm/cascadia v1.3.2 // indirect - github.com/fatih/color v1.16.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) diff --git a/go.sum b/go.sum index 5ada711..8df404c 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,7 @@ github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI= github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY= -github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= -github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= -github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk= -github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI= github.com/chromedp/cdproto v0.0.0-20230220211738-2b1ec77315c9 h1:wMSvdj3BswqfQOXp2R1bJOAE7xIQLt2dlMQDMf836VY= github.com/chromedp/cdproto v0.0.0-20230220211738-2b1ec77315c9/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.1 h1:CC7cC5p1BeLiiS2gfNNPwp3OaUxtRMBjfiw3E3k6dFA= @@ -16,8 +12,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= @@ -39,19 +33,9 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mangoumbrella/goldmark-figure v1.0.0 h1:L+ebP73dET0a2n68PV7m5oFJmwwH5GzRIJLgszR3fwo= github.com/mangoumbrella/goldmark-figure v1.0.0/go.mod h1:iIL+fhdmCQDpE0l/TKtGhokWzIbo5lo/Y2OIAcx6usI= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= @@ -90,9 +74,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/pkg/engine/anna_engine.go b/pkg/engine/anna_engine.go index 606a103..e68b093 100644 --- a/pkg/engine/anna_engine.go +++ b/pkg/engine/anna_engine.go @@ -123,7 +123,7 @@ func (e *Engine) GenerateJSONIndex(outFilePath string) { // It extracts data from the e.Templates slice // The index.json file is created during every VanillaRender() - jsonFile, err := os.Create(outFilePath + "/rendered/static/index.json") + jsonFile, err := os.Create(outFilePath + "rendered/static/index.json") if err != nil { e.ErrorLogger.Fatal(err) } diff --git a/pkg/engine/anna_engine_test.go b/pkg/engine/anna_engine_test.go index 45b43d1..c789fcf 100644 --- a/pkg/engine/anna_engine_test.go +++ b/pkg/engine/anna_engine_test.go @@ -132,7 +132,7 @@ func TestGenerateMergedJson(t *testing.T) { }, } - e.GenerateJSONIndex(TestDirPath + "json_index_test") + e.GenerateJSONIndex(TestDirPath + "json_index_test/") got_json, err := os.ReadFile(TestDirPath + "/json_index_test/rendered/static/index.json") if err != nil { diff --git a/pkg/helpers/helper.go b/pkg/helpers/helper.go index 7f86fb2..379ff37 100644 --- a/pkg/helpers/helper.go +++ b/pkg/helpers/helper.go @@ -1,16 +1,10 @@ package helpers import ( - "archive/zip" - "fmt" "io" "log" - "net/http" "os" - "path/filepath" "strings" - - "github.com/cheggaaa/pb/v3" ) const SiteDataPath string = "site/" @@ -87,91 +81,91 @@ func (h *Helper) CreateRenderedDir(fileOutPath string) { } } -func (h *Helper) Bootstrap() { - fmt.Println("Are you sure you want to proceed with the bootstrap process? (y/n)") - var confirm string - fmt.Scanln(&confirm) - if confirm != "y" { - fmt.Println("Bootstrap process cancelled.") - return - } - url := fmt.Sprintf("https://github.com/acmpesuecc/anna/archive/refs/tags/v%s.zip", version) - - output, err := os.Create("anna-dl.zip") - if err != nil { - fmt.Println("Error creating output file:", err) - return - } - defer output.Close() - response, err := http.Get(url) - if err != nil { - fmt.Println("Error downloading:", err) - return - } - defer response.Body.Close() - if response.StatusCode != http.StatusOK { - fmt.Println("Error: Server returned status", response.Status) - return - } - - bar := pb.Full.Start64(response.ContentLength) - defer bar.Finish() - reader := bar.NewProxyReader(response.Body) - - _, err = io.Copy(output, reader) - if err != nil { - fmt.Println("Error copying:", err) - return - } - ext(version) -} - -func ext(version string) { - zipFilePath := "anna-dl.zip" - zipFile, err := zip.OpenReader(zipFilePath) - if err != nil { - log.Fatal(err) - } - defer zipFile.Close() - for _, file := range zipFile.File { - zippedFile, err := file.Open() - if err != nil { - log.Fatal(err) - } - defer zippedFile.Close() - - extractedFilePath := filepath.Join(".", file.Name) // Extract to the current directory - if file.FileInfo().IsDir() { - err := os.MkdirAll(extractedFilePath, os.ModePerm) - if err != nil { - log.Fatal(err) - } - } else { - extractedFile, err := os.Create(extractedFilePath) - if err != nil { - log.Fatal(err) - } - defer extractedFile.Close() - - _, err = io.Copy(extractedFile, zippedFile) - if err != nil { - log.Fatal(err) - } - } - } - - // Bootstrap the base theme - helper := &Helper{ - ErrorLogger: log.New(os.Stderr, "ERROR: ", log.LstdFlags), - } - helper.CopyDirectoryContents(fmt.Sprintf("anna-%s/site/", version), "site/") - err = os.Remove("anna-dl.zip") - if err != nil { - log.Fatal("Error cleaning-up zip file:", err) - } - err = os.RemoveAll(fmt.Sprintf("anna-%s", version)) - if err != nil { - log.Fatal("Error deleting directory:", err) - } - log.Println("Bootstrapped base theme") -} +// func (h *Helper) Bootstrap() { +// fmt.Println("Are you sure you want to proceed with the bootstrap process? (y/n)") +// var confirm string +// fmt.Scanln(&confirm) +// if confirm != "y" { +// fmt.Println("Bootstrap process cancelled.") +// return +// } +// url := fmt.Sprintf("https://github.com/acmpesuecc/anna/archive/refs/tags/v%s.zip", version) + +// output, err := os.Create("anna-dl.zip") +// if err != nil { +// fmt.Println("Error creating output file:", err) +// return +// } +// defer output.Close() +// response, err := http.Get(url) +// if err != nil { +// fmt.Println("Error downloading:", err) +// return +// } +// defer response.Body.Close() +// if response.StatusCode != http.StatusOK { +// fmt.Println("Error: Server returned status", response.Status) +// return +// } + +// bar := pb.Full.Start64(response.ContentLength) +// defer bar.Finish() +// reader := bar.NewProxyReader(response.Body) + +// _, err = io.Copy(output, reader) +// if err != nil { +// fmt.Println("Error copying:", err) +// return +// } +// ext(version) +// } + +// func ext(version string) { +// zipFilePath := "anna-dl.zip" +// zipFile, err := zip.OpenReader(zipFilePath) +// if err != nil { +// log.Fatal(err) +// } +// defer zipFile.Close() +// for _, file := range zipFile.File { +// zippedFile, err := file.Open() +// if err != nil { +// log.Fatal(err) +// } +// defer zippedFile.Close() + +// extractedFilePath := filepath.Join(".", file.Name) // Extract to the current directory +// if file.FileInfo().IsDir() { +// err := os.MkdirAll(extractedFilePath, os.ModePerm) +// if err != nil { +// log.Fatal(err) +// } +// } else { +// extractedFile, err := os.Create(extractedFilePath) +// if err != nil { +// log.Fatal(err) +// } +// defer extractedFile.Close() + +// _, err = io.Copy(extractedFile, zippedFile) +// if err != nil { +// log.Fatal(err) +// } +// } +// } + +// // Bootstrap the base theme +// helper := &Helper{ +// ErrorLogger: log.New(os.Stderr, "ERROR: ", log.LstdFlags), +// } +// helper.CopyDirectoryContents(fmt.Sprintf("anna-%s/site/", version), "site/") +// err = os.Remove("anna-dl.zip") +// if err != nil { +// log.Fatal("Error cleaning-up zip file:", err) +// } +// err = os.RemoveAll(fmt.Sprintf("anna-%s", version)) +// if err != nil { +// log.Fatal("Error deleting directory:", err) +// } +// log.Println("Bootstrapped base theme") +// } diff --git a/pkg/helpers/helper_test.go b/pkg/helpers/helper_test.go index a04bf56..68529f8 100644 --- a/pkg/helpers/helper_test.go +++ b/pkg/helpers/helper_test.go @@ -3,25 +3,69 @@ package helpers_test import ( "io/fs" "log" + "os" + "slices" "testing" - "testing/fstest" + + "github.com/acmpesuecc/anna/pkg/helpers" ) -type Helper struct { - ErrorLogger *log.Logger - SiteDataPath string -} +var HelperTestDirPath = "../../test/helpers/" func TestCopyDirectoryContents(t *testing.T) { - t.Run("Testinf copying contents from A to B", func(t *testing.T) { - fsMock := fstest.MapFS{ - "index.md": {Data: []byte("# Index Page")}, - "about.md": {Data: []byte("# About Page")}, + t.Run("recursively copying directory contents", func(t *testing.T) { + helper := helpers.Helper{ + ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), + } + helper.CopyDirectoryContents(HelperTestDirPath+"copy_dir/", HelperTestDirPath+"copy_dir/rendered/") + + baseDirFS := os.DirFS(HelperTestDirPath + "copy_dir/input_dir/") + TraverseDirectory(baseDirFS, t) + }) +} + +func TraverseDirectory(baseDirFS fs.FS, t *testing.T) error { + fs.WalkDir(baseDirFS, ".", func(path string, dir fs.DirEntry, err error) error { + if !dir.IsDir() { + got_file, err := os.ReadFile(HelperTestDirPath + "copy_dir/input_dir/" + path) + if err != nil { + t.Errorf("%v", err) + } + + want_file, err := os.ReadFile(HelperTestDirPath + "copy_dir/rendered/input_dir/" + path) + if err != nil { + t.Errorf("%v", err) + } + + if !slices.Equal(got_file, want_file) { + t.Errorf("The expected and generated files can be found in %s", HelperTestDirPath) + } + } + return nil + }) + return nil +} - fs.WalkDir(fsMock, ".", func(path string, d fs.DirEntry, err error) error { - return nil - }) +func TestCopyFiles(t *testing.T) { + t.Run("copy file and create nested parent directories", func(t *testing.T) { + helper := helpers.Helper{ + ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), + } + helper.CopyFiles(HelperTestDirPath+"copy_files/input.txt", HelperTestDirPath+"copy_files/rendered/output.txt") + got_file, err := os.ReadFile(HelperTestDirPath + "copy_files/input.txt") + if err != nil { + t.Errorf("%v", err) + } + + want_file, err := os.ReadFile(HelperTestDirPath + "copy_files/rendered/output.txt") + if err != nil { + t.Errorf("%v", err) + } + + if !slices.Equal(got_file, want_file) { + t.Errorf("The expected and generated files can be found in %s", HelperTestDirPath) + } }) } diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index f1f5219..27870da 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -41,6 +41,7 @@ type Frontmatter struct { Description string `yaml:"description"` PreviewImage string `yaml:"previewimage"` Tags []string `yaml:"tags"` + TOC bool `yaml:"toc"` Authors []string `yaml:"authors"` // Head is specifically used for @@ -239,7 +240,7 @@ func (p *Parser) ParseMarkdownContent(filecontent string) (Frontmatter, string, var parsedMarkdown bytes.Buffer var md goldmark.Markdown - if parsedFrontmatter.Type == "post" { + if parsedFrontmatter.Type == "post" || parsedFrontmatter.TOC { md = goldmark.New( goldmark.WithParserOptions(parser.WithAutoHeadingID()), goldmark.WithExtensions( @@ -292,12 +293,12 @@ func (p *Parser) DateParse(date string) time.Time { } func (p *Parser) ParseConfig(inFilePath string) { - // Check if the configuration file exists - _, err := os.Stat(inFilePath) - if os.IsNotExist(err) { - p.Helper.Bootstrap() - return - } + // // Check if the configuration file exists + // _, err := os.Stat(inFilePath) + // if os.IsNotExist(err) { + // p.Helper.Bootstrap() + // return + // } // Read and parse the configuration file configFile, err := os.ReadFile(inFilePath) diff --git a/pkg/parser/parser_test.go b/pkg/parser/parser_test.go index 250ba97..419d8bb 100644 --- a/pkg/parser/parser_test.go +++ b/pkg/parser/parser_test.go @@ -170,3 +170,65 @@ func TestParseRobots(t *testing.T) { } }) } + +// func TestParseBacklink(t *testing.T) { + +// got_parser := parser.Parser{ +// Notes: make(map[template.URL]parser.Note), +// ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), +// } + +// // creating dummy notes for testing + +// got_parser.Notes[template.URL("notes/test/test.md")] = parser.Note{ +// Frontmatter: parser.Frontmatter{ +// Title: "head note", +// Type: "note", +// Head: true, +// }, +// Body: template.HTML("This is a [[backlink]]"), +// } + +// got_parser.Notes[template.URL("notes/test/backlink.md")] = parser.Note{ +// Frontmatter: parser.Frontmatter{ +// Title: "backlink", +// Type: "note", +// }, +// Body: template.HTML("Content of note."), +// } + +// t.Run("testing backlink parsing in body of markdown files", func(t *testing.T) { + +// got_parser.ParseBacklink("notes/test/test.md") + +// want_parser := parser.Parser{ +// Notes: map[template.URL]parser.Note{ +// template.URL("notes/test/test.md"): parser.Note{ +// Frontmatter: parser.Frontmatter{ +// Title: "head note", +// Type: "note", +// Head: true, +// }, +// Body: template.HTML("This is a [[backlink]] here"), +// LinkedNoteURLs: []template.URL{"notes/test/backlink.md"}, +// }, + +// template.URL("notes/test/backlink.md"): parser.Note{ +// Frontmatter: parser.Frontmatter{ +// Title: "backlink", +// Type: "note", +// }, +// Body: template.HTML("Content of note."), +// }, +// }, +// ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), +// } + +// got_list := got_parser.Notes["notes/test/test.md"].LinkedNoteURLs +// want_list := want_parser.Notes["notes/test/test.md"].LinkedNoteURLs + +// if !slices.Equal(got_list, want_list) { +// t.Errorf("got %v, want %v", got_list, want_list) +// } +// }) +// } diff --git a/pkg/parser/zettel_parser.go b/pkg/parser/zettel_parser.go index bd3902a..50aff08 100644 --- a/pkg/parser/zettel_parser.go +++ b/pkg/parser/zettel_parser.go @@ -114,11 +114,13 @@ func (p *Parser) ParseBacklink(noteURL template.URL) { MarkdownBody: note.MarkdownBody, LinkedNoteURLs: note.LinkedNoteURLs, } + // fmt.Println(p.Notes[noteURL]) } func (p *Parser) ValidateBackLink(noteTitle string) (template.URL, error) { for _, note := range p.Notes { if note.Frontmatter.Title == noteTitle { + // fmt.Println("URL: ", note.CompleteURL) return note.CompleteURL, nil } } diff --git a/site/content/developer-guide.md b/site/content/developer-guide.md new file mode 100644 index 0000000..3dc0bbb --- /dev/null +++ b/site/content/developer-guide.md @@ -0,0 +1,27 @@ +--- +date: 2024-04-28 +title: Developer Guide +type: page +toc: true +--- + +# Developer Guide + +--- + +## Contributing to Anna + +Detailed documentation for our SSG can be found: [here](https://anna-docs.netlify.app/) + +If you have git installed, clone our repository and build against the latest commit + +```sh +git clone github.com/acmpesuecc/anna; cd anna +go build +``` + +--- + +## Profiling + +The live profile data of the application can be viewed during live reload by navigating to `http://localhost:8000/debug/pprof` diff --git a/site/content/docs-update.md b/site/content/docs-update.md index c3cfeb2..3e3a5f4 100644 --- a/site/content/docs-update.md +++ b/site/content/docs-update.md @@ -4,13 +4,9 @@ title: Anna Documentation Updates type: page --- -- we are common mark compliant -- page and posts field to frontmatter -- recursively copies contents/ dir, so images and static content can be added in sub-dirs -- goldmark extension details: mermaid, toc, figure(Add caption beloe link, etc) - ## developer guide - profiling: + - live pprof during live reload - creating .pprof files diff --git a/site/content/docs.md b/site/content/docs.md index 29c2eeb..c197f81 100644 --- a/site/content/docs.md +++ b/site/content/docs.md @@ -1,87 +1,119 @@ --- -date: 2024-04-10 +date: 2024-04-28 title: Anna Documentation type: page +toc: true --- -# Anna - -```text - ___ - / | ____ ____ ____ _ - / /| | / __ \/ __ \/ __ `/ - / ___ |/ / / / / / / /_/ / -/_/ |_/_/ /_/_/ /_/\__,_/ - -A static site generator in go -``` - -Inspired by [Hugo](https://gohugo.io) and [Saaru](https://github.com/anirudhRowjee/saaru), this static site generator aims to take performance to the next level with parallel rendering, live reload and so much more, all in Go. - -Pronounced: `/ɐnĖÉ/` which means rice in Kannada šŸš - -This Project is a part of the ACM PESU-ECC's yearly [AIEP](https://acmpesuecc.github.io/aiep) program, and is maintained by [Adhesh Athrey](https://github.com/DedLad), [Nathan Paul](https://github.com/polarhive), [Anirudh Sudhir](https://github.com/anirudhsudhir), and [Aditya Hegde](https://github.com/bwaklog) - --- + ## Directory structure The ssg currently requires the following directory structure ```text -/anna -ā”œā”€ā”€ /cmd -ā”œā”€ā”€ /pkg -ā”‚Ā Ā  ā”œā”€ā”€ /engine -ā”‚Ā Ā  ā”œā”€ā”€ /helpers -ā”‚Ā Ā  ā””ā”€ā”€ /parser -ā”œā”€ā”€ /site -ā”‚ Ā Ā  ā”œā”€ā”€ /content -ā”‚ ā”‚Ā Ā  ā”‚Ā Ā  ā”œā”€ā”€ /posts -ā”‚ ā”‚ ā”‚ ā”‚ ā””ā”€ā”€ sample.md -ā”‚ ā”‚ ā”‚Ā Ā  ā””ā”€ā”€ā”€ /notes -ā”‚ Ā Ā  ā”‚Ā Ā  ā””ā”€ā”€ index.md -ā”‚ ā”œā”€ā”€ /layout -ā”‚ ā”‚Ā Ā  ā”œā”€ā”€ config.yml (This file is necessary and cannot be omitted) -ā”‚ ā”‚Ā Ā  ā”œā”€ā”€ page.html (This file is necessary and cannot be omitted) -ā”‚ ā”‚Ā Ā  ā”œā”€ā”€ posts.html (This file is necessary to create a 'Posts' section) -ā”‚ ā”‚Ā Ā  ā””ā”€ā”€ā”€ /partials -ā”‚ ā”‚Ā Ā  Ā Ā  ā””ā”€ā”€ partials for page -ā”‚ ā”œā”€ā”€ /static -ā”‚ ā”‚Ā  ā”œā”€ā”€ /fonts -ā”‚ ā”‚Ā  ā”œā”€ā”€ /images -ā”‚ ā”‚Ā  ā”œā”€ā”€ plane.jpg -ā”‚ ā”‚Ā  ā”œā”€ā”€ /scripts -ā”‚ ā”‚Ā  ā””ā”€ā”€ style.css -ā”‚ Ā Ā  ā”” /rendered (This directory is created by the ssg) -ā””ā”€ā”€ /test (Stores mock data required to test the SSG) - ā”œā”€ā”€ /engine - ā”‚Ā Ā  ā”œā”€ā”€ /merged_data_test - ā”‚Ā Ā  ā”œā”€ā”€ /render_engine_generated - ā”‚Ā Ā  ā”œā”€ā”€ /render_page - ā”‚Ā Ā  ā”œā”€ā”€ /render_tags - ā”‚Ā Ā  ā””ā”€ā”€ /render_user_defined - ā””ā”€ā”€ /parser - ā”œā”€ā”€ /input - ā”œā”€ā”€ /layout - ā””ā”€ā”€ /parse_md +site +ā”œā”€ā”€ content +ā”‚Ā Ā  ā”œā”€ā”€ docs.md +ā”‚Ā Ā  ā”œā”€ā”€ index.md* +ā”‚Ā Ā  ā”œā”€ā”€ notes +ā”‚Ā Ā  ā”‚Ā Ā  ā””ā”€ā”€ anna +ā”‚Ā Ā  ā”‚Ā Ā  ā””ā”€ā”€ zettelkasten.md +ā”‚Ā Ā  ā”œā”€ā”€ posts +ā”‚Ā Ā  ā”‚Ā Ā  ā”œā”€ā”€ bench.md +ā”‚Ā Ā  ā”‚Ā Ā  ā”œā”€ā”€ building-anna +ā”‚Ā Ā  ā”‚Ā Ā  ā”‚Ā Ā  ā”œā”€ā”€ images +ā”‚Ā Ā  ā”‚Ā Ā  ā”‚Ā Ā  ā”‚Ā Ā  ā”œā”€ā”€ bench.png +ā”‚Ā Ā  ā”‚Ā Ā  ā”‚Ā Ā  ā”‚Ā Ā  ā””ā”€ā”€ wizard.gif +ā”‚Ā Ā  ā”‚Ā Ā  ā”‚Ā Ā  ā”œā”€ā”€ index.md +ā”‚Ā Ā  ā”‚Ā Ā  ā””ā”€ā”€ weekly-progress +ā”‚Ā Ā  ā”‚Ā Ā  ā”œā”€ā”€ week-1.md +ā”‚Ā Ā  ā”‚Ā Ā  ā”œā”€ā”€ week-2.md +ā”‚Ā Ā  ā”‚Ā Ā  ā””ā”€ā”€ week-3.md +ā”œā”€ā”€ layout +ā”‚Ā Ā  ā”œā”€ā”€ config.yml* +ā”‚Ā Ā  ā”œā”€ā”€ note.html* +ā”‚Ā Ā  ā”œā”€ā”€ notes.html* +ā”‚Ā Ā  ā”œā”€ā”€ page.html* +ā”‚Ā Ā  ā”œā”€ā”€ partials +ā”‚Ā Ā  ā”‚Ā Ā  ā”œā”€ā”€ head.html +ā”‚Ā Ā  ā”œā”€ā”€ posts.html* +ā”‚Ā Ā  ā”œā”€ā”€ robots.txt* +ā”‚Ā Ā  ā”œā”€ā”€ tag-subpage.html* +ā”‚Ā Ā  ā””ā”€ā”€ tags.html* +ā”œā”€ā”€ public +ā””ā”€ā”€ static + ā”œā”€ā”€ fonts + ā”‚Ā Ā  ā”œā”€ā”€ VictorMono + ā”‚Ā Ā  ā”‚Ā Ā  ā””ā”€ā”€ victormono_italics.ttf + ā”œā”€ā”€ scripts + ā”‚Ā Ā  ā””ā”€ā”€ light.js + ā”œā”€ā”€ style.css + ā”œā”€ā”€ styles + Ā Ā  ā””ā”€ā”€ tokyo-dark.css ``` +Files marked \* are required and cannot be omitted + +Anna must be run from the parent of the site/ dir + +--- + ## Description of the directory structure - All of the site data, including the content, configuration and static files, are stores in site/. The rendered/ directory generated by ssg is also stored in site/. -- The markdown content for the site is stored in `content/` it can contain subdirectories as the folder is recursively rendered. -- Static assets such as images and fonts are stored in `static/` +- The markdown content for the site is stored in `content/`. It can contain subdirectories along with images as the folder is recursively rendered. + - The contents of this dir is rendered to the root of `rendered/` + - The `notes/` folder holds markdown notes which are rendered by a different process and include various note-specific features +- Static assets such as fonts are stored in `static/` - Scripts are stored in the `scripts/` dir in `static/` - The layout of the site is configured using html files in `layout/` - The `config.yml` file stores the configuration of the site and includes details such as the baseURL - - The `page.html` file defines the layout of a basic page of the site - - The `posts.html` file defines the layout of a page displaying all the posts of the site + - The `page.html`, `posts.html` and other necessary layouts define the structure of the various pages of the site such as posts.html, tags.html and regular pages - The layout files can be composed of smaller html files which are stored in the `partials/` folder +- Contents in `public/` are rendered to the root of `rendered/` + +--- ## Building layouts -Each layout file(except `posts.html`, `tags.html` & `notes.html`) can access any data from the entire ssg +Each layout file can access any data from the entire ssg + +The `posts.html` layout can access the following data + +- `{{.DeepDataMerge}}` +- `{{.PageURL}}` +- `{{.TemplateData}}` + +The `tags.html` page can access the following data + +- `{{.DeepDataMerge}}` +- `{{.PageURL}}` +- `{{.TemplateData}}` +- `{{.TagNames}}` + +The remaining pages can access the following data + +- `{{.DeepDataMerge}}` +- `{{.PageURL}}` + +### PageURL + +The `{{.PageURL}}` is of the form `index.html`, `posts/tech/go.html` and so on. + +### Elements stored in `DeepDataMerge` + +- `{{.DeepDataMerge.Templates}}` - A map that stores the template data of all the pages of the site for the particular url(the URL is the PageURL for the speicified page) +- `{{.DeepDataMerge.Tags}}` - A map that stores the template data of the tag sub-pages for a particular tag url +- `{{.DeepDataMerge.TagsMap}}` - A map that stores a slice of templates of all posts for a particular tag url +- `{{.DeepDataMerge.LayoutConfig}}` - Stores the layout parsed from `config.yml` +- `{{.DeepDataMerge.Posts}}` - Stores a slice of the template data of all posts +- `{{.DeepDataMerge.Notes}}` - Similar to `Posts` but for all the notes part of the site +- `{{.DeepDataMerge.LinkStore}}` - Stores a map which contains a slice of pointers to the _linked notes_. +- `{{.DeepDataMerge.JSONIndex}}` - Stores the JSON index generated for a particular site (primarily used for search and graphing of tags) + +### Accessing specific page data The URL for the current page can be accessed using `{{.PageURL}}` @@ -92,7 +124,11 @@ To access the data for a particular page, use Go templating syntax: {{$PageData.CompleteURL}} ``` -To access the page data for `posts.html`, `tags.html` and partials, set {{$PageData := .TemplateData}} +To access the page data for `posts.html`, `tags.html` and their respective partials, set + +```html +{{$PageData := .TemplateData}} +``` All of the following page data fields can be accessed in the above manner: @@ -101,51 +137,83 @@ All of the following page data fields can be accessed in the above manner: - `{{$PageData.Frontmatter.[Tagname]}}` : Returns the value of the frontmatter tag - Example: `{{$PageData.Frontmatter.Title}}` : Returns the value of the title tag - `{{$PageData.Body}}` : Returns the markdown body rendered to HTML -- `{{$PageData.Layout.[Tagname]}}`: Returns the particular configuration detail of the page - - Example: `{{$PageData.Layout.Navbar}}` : Returns a string slice with the names of all the navbar elements - -In addition to page data, the following fields can be accessed: - -- `{{.DeepDataMerge.Tags}}` - A map that stores the template of the tag sub-pages for a particular tag url -- `{{.DeepDataMerge.TagsMap}}` - A map that stores a slice of templates of all posts for a particular tag url -- `{{.DeepDataMerge.LayoutConfig}}` - Stores the layout parsed from `config.yml` -- `{{.DeepDataMerge.Posts}}` - Stores a slice of templates of all posts -- `{{.DeepDataMerge.JSONIndex}}` - Stores the JSON index generated for a particular site (primarily used for search and graphing of tags) -- `{{.DeepDataMerge.LinkStore}}` - Stores a map which contains a slice of pointers to the *linked notes*. -- `{{.DeepDataMerge.Notes}}` - Similar to `Posts` but for all the notes part of the site - -## Notes - -1. Images: To add images, add it to the 'static/' folder or a subdirectory under it. Use `/static/[imagename.format]` as the image link format in the markdown files. +--- -2. CSS: CSS can be added in the following ways: +## Frontmatter -- In an external file in the `static/` directory and linked to the layout files +Metadata such as the title of the page can be added as frontmatter to the markdown files in the YAML format. +This metadata can be accessed from the layout files with the appropriate syntax. - - To link the stylesheet, use the `baseURL` along with the relative path - - Example: `` - -- Placed inside `` tags in the `` of the layout files -- Inline with the html elements - -3. Frontmatter: Metadata such as the title of the page can be added as frontmatter to the markdown files in the YAML format. Currently, the following tags are supported: +Currently, the following frontmatter tags are supported: - `title` : The title of the current page - `date`: The date of the current page - `draft`: When set to 'true', the current page is not rendered unless the '-d' flag is used - `scripts`: Stores the page-level scripts to be added -- `type`: Sets the type of the page. Use type 'post' for posts & `note` for notes +- `type`: Sets the type of the page. Use type `page` for regular pages, `post` for posts & `note` for notes + +#### Important + +> anna will not render a page unless it contains the `type` field in the frontmatter + - `description`: Stores the description of the current post previewed in posts.html - `previewimage`: Stores the preview image of the current page - `tags`: Stores the tags of the particular page +- `toc`: When set to 'true', a table of contents is rendered for the current page + +#### Important + +> anna automatically renders a table of contents for every file of `type: post` + - `authors`: Stores (multiple) author/s of a particular page - `head`: Users need to manually specify head of the zettel in the frontmatter. Only head notes will be a part of `notes.html` -(**The above tags are Frontmatter tags**) +--- + +## Body + +Anna uses [Goldmark](https://github.com/yuin/goldmark) to render markdown files, which is CommonMark compliant + +A few useful goldmark extensions have been included: + +- [anchor](https://github.com/abhinav/goldmark-anchor) + - adds support for anchors next to all headers +- [figure](https://github.com/mangoumbrella/goldmark-figure) + - parse markdown paragraphs that start with an image into HTML `
` elements +- [mermaid](https://github.com/abhinav/goldmark-mermaid) + - adds support for [Mermaid](https://mermaid.js.org) diagrams +- [toc](https://github.com/abhinav/goldmark-toc) + - adds support for rendering a table-of-contents + +--- + +## Static assets + +### Images + +Images can be added to the `content/` dir, `public/` dir or the `static/` dir. +The contents of the `static/` and `public/` directories and the non-markdown files present in the `content/` dir are copied to `rendered/` + +The images can be referenced in the markdown files via their relative or absolute paths -4. config.yml: This file stores additional information regarding the layout of the site +### CSS + +CSS can be added in the following ways: + +- In an external file in the `static/` directory and linked to the layout files + + Example: `` + +- Placed inside `` tags in the `` of the layout files +- Inline with the html elements + +--- + +## Site configuration + +The config.yml file stores additional information regarding the layout of the site +It contains the following fields: - `navbar`: Stores the links to be added to the navbar (same name as the markdown files) - `baseURL`: Stores the base URL of the site @@ -153,8 +221,6 @@ In addition to page data, the following fields can be accessed: - `siteScripts`: Stores the javascript files to be included with every page - `author`: Stores the author of the site -(**The above tags are Layout tags**) - ### Sample `config.yml` ```yml @@ -177,91 +243,27 @@ author: Anna --- -# Notes Usage +## Notes Anna provides users with functionality of maintaining notes and sharing them. Notes opens another set of functionality for anna. Users can create under the `site/notes` directory. Besides similar use cases as a post, notes can be short snippets of information, code or even some kind of list that the users want. It supports some important aspects of [zettelkasten](https://zettelkasten.de/overview/) where users can link notes to each other, and organise similar posts in a zettel. We aren't trying to re-invent the process of making an editor that helps users maintain these zettels as there are already some fantastic applications, namely [Obsidian](https://obsidian.md/), [Ginko Writer](https://app.gingkowriter.com) and [Evergreen Notes](https://evergreennotes.com/). Our application as a rather needs to provide a generator to stitch these notes together to make it accessible on the site. -## Directory structure +### Notes directory structure ```text /notes ā”œā”€ā”€ /zettel A -ā””ā”€ā”€ /zettel B - Ā Ā  ā”œā”€ā”€ note A +ā””ā”€ā”€ /zettel B + Ā Ā  ā”œā”€ā”€ note A Ā Ā  ā”œā”€ā”€ note B - Ā Ā  ā””ā”€ā”€ note C + Ā Ā  ā””ā”€ā”€ note C ``` -## Linking Notes +### Linking Notes -Notes can be linked by using callouts in markdown files such as `[[]]`. The parser will validate these links during the runtime. It checks whether there are existing valid notes with a title matching the content of the callout. If not an error is thrown and you wont be able to compile the site. +Notes can be linked by using callouts in markdown files such as `[[]]`. The parser will validate these links during the runtime. It checks whether there are existing valid notes with a title matching the content of the callout. If not an error is thrown and you wont be able to compile the site. For example. If you have a note with the title `Note A` and you would like to reference it else where in another note (could even be part of another zettel). Then `[[Note A]]` would be the appropriate callout to use it. --- - -## Anna Usage - - -### Installing anna from releases - -Run this in the appropriate folder. Note that if you don't have a site dir with the pre-requisite layout template; anna proceeds to fetch the default site dir from our GitHub repository - -```sh -curl -L https://github.com/acmpesuecc/anna/releases/download/version-tag/releases-name.tar.gz > anna.tar.gz -tar -xvf anna.tar.gz # unzip the tar file -rm anna.tar.gz # removing the tar file - -# here you could add anna to your path if you want and use in in any directory -./anna # runs anna. The instructions are given below -``` - -### Brew taps for MacOS - -To get anna set up on your mac using brew taps, heres the repo you need to tap off from - -```sh -brew tap anna-ssg/anna -brew install anna - -# to run anna -anna -``` - -### Installing anna with go - -```sh -go run github.com/acmpesuecc/anna@v2.0.0 -``` - -### Flags for usage and purpose - -```text -Usage: - anna [flags] - -Flags: - -a, --addr string ip address to serve rendered content to (default "8000") - -d, --draft renders draft posts - -h, --help help for anna - -l, --layout validates html layouts - -p, --prof enable profiling - -s, --serve serve the rendered content - -v, --version prints current version number - -w, --webconsole wizard to setup anna -``` - - -## Contributing to Anna - -Detailed documentation for our SSG can be found: [here](https://anna-docs.netlify.app/) - -If you have git installed, clone our repository and build against the latest commit - -```sh -git clone github.com/acmpesuecc/anna; cd anna -go build -``` - diff --git a/site/content/quick-start.md b/site/content/quick-start.md new file mode 100644 index 0000000..411b150 --- /dev/null +++ b/site/content/quick-start.md @@ -0,0 +1,62 @@ +--- +date: 2024-04-28 +title: Quick Start +type: page +toc: true +--- + +# Quick Start + +--- + +## Installation + +### Installing anna from releases + +Run this in the appropriate folder. Note that if you don't have a site dir with the pre-requisite layout template; anna proceeds to fetch the default site dir from our GitHub repository + +```sh +curl -L https://github.com/acmpesuecc/anna/releases/download/version-tag/releases-name.tar.gz > anna.tar.gz +tar -xvf anna.tar.gz # unzip the tar file +rm anna.tar.gz # removing the tar file + +# here you could add anna to your path if you want and use in in any directory +./anna # runs anna. The instructions are given below +``` + +### Brew taps for MacOS + +To get anna set up on your mac using brew taps, heres the repo you need to tap off from + +```sh +brew tap anna-ssg/anna +brew install anna + +# to run anna +anna +``` + +### Installing anna with go + +```sh +go run github.com/acmpesuecc/anna@v2.0.0 +``` + +--- + +## Flags for usage and purpose + +```text +Usage: + anna [flags] + +Flags: + -a, --addr string ip address to serve rendered content to (default "8000") + -d, --draft renders draft posts + -h, --help help for anna + -l, --layout validates html layouts + -p, --prof enable profiling + -s, --serve serve the rendered content + -v, --version prints current version number + -w, --webconsole wizard to setup anna +``` diff --git a/site/layout/config.yml b/site/layout/config.yml index 39bd404..d22fb8c 100644 --- a/site/layout/config.yml +++ b/site/layout/config.yml @@ -1,6 +1,8 @@ navbar: - index + - quick-start - docs + - developer-guide - tags - notes - posts diff --git a/site/public/public.txt b/site/public/public.txt new file mode 100644 index 0000000..c799758 --- /dev/null +++ b/site/public/public.txt @@ -0,0 +1 @@ +This is a test .txt file that will be rendered to the root of rendered/ diff --git a/test/engine/json_index_test/want_index.json b/test/engine/json_index_test/want_index.json index ae28840..c563525 100644 --- a/test/engine/json_index_test/want_index.json +++ b/test/engine/json_index_test/want_index.json @@ -1 +1 @@ -{"docs.md":{"CompleteURL":"docs.html","Frontmatter":{"Title":"Anna Documentation","Date":"","Draft":false,"JSFiles":null,"Type":"","Description":"","PreviewImage":"","Tags":null,"Authors":null,"Head":false},"Tags":null}} +{"docs.md":{"CompleteURL":"docs.html","Frontmatter":{"Title":"Anna Documentation","Date":"","Draft":false,"JSFiles":null,"Type":"","Description":"","PreviewImage":"","Tags":null,"TOC":false,"Authors":null,"Head":false},"Tags":null}} diff --git a/test/helpers/copy_dir/input_dir/sub_dir2/sub_sub_dir2/file2.txt b/test/helpers/copy_dir/input_dir/sub_dir2/sub_sub_dir2/file2.txt new file mode 100644 index 0000000..d344db8 --- /dev/null +++ b/test/helpers/copy_dir/input_dir/sub_dir2/sub_sub_dir2/file2.txt @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum sit amet pede facilisis laoreet. Donec lacus nunc, viverra nec, blandit vel, egestas et, augue. Vestibulum tincidunt malesuada tellus. Ut ultrices ultrices enim. Curabitur sit amet mauris. Morbi in dui quis est pulvinar ullamcorper. diff --git a/test/helpers/copy_dir/input_dir/sub_dir_1/file1.txt b/test/helpers/copy_dir/input_dir/sub_dir_1/file1.txt new file mode 100644 index 0000000..d344db8 --- /dev/null +++ b/test/helpers/copy_dir/input_dir/sub_dir_1/file1.txt @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum sit amet pede facilisis laoreet. Donec lacus nunc, viverra nec, blandit vel, egestas et, augue. Vestibulum tincidunt malesuada tellus. Ut ultrices ultrices enim. Curabitur sit amet mauris. Morbi in dui quis est pulvinar ullamcorper. diff --git a/test/helpers/copy_files/input.txt b/test/helpers/copy_files/input.txt new file mode 100644 index 0000000..d344db8 --- /dev/null +++ b/test/helpers/copy_files/input.txt @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum sit amet pede facilisis laoreet. Donec lacus nunc, viverra nec, blandit vel, egestas et, augue. Vestibulum tincidunt malesuada tellus. Ut ultrices ultrices enim. Curabitur sit amet mauris. Morbi in dui quis est pulvinar ullamcorper. From a5aeda3032cc5bddd98b3bd28107944ede0ccfa7 Mon Sep 17 00:00:00 2001 From: Anirudh Sudhir Date: Wed, 1 May 2024 12:18:07 +0530 Subject: [PATCH 2/3] test: add and fix zettel/ tests Co-authored-by: Aditya Hegde --- .gitignore | 3 + pkg/parser/parser_test.go | 211 ++++++++++++++++++------------------ pkg/parser/zettel_parser.go | 5 - 3 files changed, 109 insertions(+), 110 deletions(-) diff --git a/.gitignore b/.gitignore index 8518e0e..d90fdd6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,12 @@ anna !anna/ *.exe + + **/.DS_Store *.prof dist/ +.idea/ #Test directories **/rendered/ diff --git a/pkg/parser/parser_test.go b/pkg/parser/parser_test.go index 419d8bb..a8903a9 100644 --- a/pkg/parser/parser_test.go +++ b/pkg/parser/parser_test.go @@ -13,62 +13,62 @@ import ( const TestDirPath = "../../test/parser/" -func TestAddFileandRender(t *testing.T) { - got_parser := parser.Parser{ +func TestAddFileAndRender(t *testing.T) { + gotParser := parser.Parser{ Templates: make(map[template.URL]parser.TemplateData), TagsMap: make(map[template.URL][]parser.TemplateData), ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), } - want_layout := parser.LayoutConfig{ + wantLayout := parser.LayoutConfig{ Navbar: []string{"index", "docs", "tags", "posts"}, BaseURL: "example.org", SiteTitle: "ssg", Author: "Anna", } - got_parser.LayoutConfig = want_layout + gotParser.LayoutConfig = wantLayout t.Run("parsing data out of one markdown post", func(t *testing.T) { inputMd, err := os.ReadFile(TestDirPath + "parse_md/md_inp.md") if err != nil { t.Errorf("%v", err) } - want_parser := parser.Parser{ + wantParser := parser.Parser{ Templates: make(map[template.URL]parser.TemplateData), TagsMap: make(map[template.URL][]parser.TemplateData), - ErrorLogger: got_parser.ErrorLogger, + ErrorLogger: gotParser.ErrorLogger, } - sample_frontmatter, _, markdownContent, parseSuccess := got_parser.ParseMarkdownContent(string(inputMd)) - sample_body := "sample_body" + sampleFrontmatter, _, markdownContent, parseSuccess := gotParser.ParseMarkdownContent(string(inputMd)) + sampleBody := "sample_body" if !parseSuccess { return } filename := "testpost.md" - fileurl := "testpost.html" - want_parser.MdFilesName = append(want_parser.MdFilesName, filename) - want_parser.MdFilesPath = append(want_parser.MdFilesPath, filename) - want_page := parser.TemplateData{ - CompleteURL: template.URL(fileurl), - Date: want_parser.DateParse(sample_frontmatter.Date).Unix(), - Frontmatter: sample_frontmatter, - Body: template.HTML(sample_body), + fileURL := "testpost.html" + wantParser.MdFilesName = append(wantParser.MdFilesName, filename) + wantParser.MdFilesPath = append(wantParser.MdFilesPath, filename) + wantPage := parser.TemplateData{ + CompleteURL: template.URL(fileURL), + Date: wantParser.DateParse(sampleFrontmatter.Date).Unix(), + Frontmatter: sampleFrontmatter, + Body: template.HTML(sampleBody), // Layout: want_layout, } - want_parser.LayoutConfig = want_layout + wantParser.LayoutConfig = wantLayout - want_parser.Templates[template.URL("testpost.html")] = want_page - for _, tag := range sample_frontmatter.Tags { - want_parser.TagsMap[template.URL(tag)] = append(want_parser.TagsMap[template.URL(tag)], want_page) + wantParser.Templates["testpost.html"] = wantPage + for _, tag := range sampleFrontmatter.Tags { + wantParser.TagsMap[template.URL(tag)] = append(wantParser.TagsMap[template.URL(tag)], wantPage) } - if sample_frontmatter.Type == "post" { - want_parser.Posts = append(want_parser.Posts, want_page) + if sampleFrontmatter.Type == "post" { + wantParser.Posts = append(wantParser.Posts, wantPage) } - got_parser.AddFile("", filename, sample_frontmatter, markdownContent, sample_body) + gotParser.AddFile("", filename, sampleFrontmatter, markdownContent, sampleBody) - if !reflect.DeepEqual(got_parser, want_parser) { - t.Errorf("want %v; \ngot %v", want_parser, got_parser) + if !reflect.DeepEqual(gotParser, wantParser) { + t.Errorf("want %v; \ngot %v", wantParser, gotParser) // t.Errorf("please see the files yourself") } }) @@ -86,15 +86,15 @@ func TestParseMarkdownContent(t *testing.T) { t.Errorf("%v", err) } - _, body_got, _, parseSuccess := p.ParseMarkdownContent(string(inputMd)) + _, bodyGot, _, parseSuccess := p.ParseMarkdownContent(string(inputMd)) if parseSuccess { - body_want, err := os.ReadFile(TestDirPath + "parse_md/html_want_output.html") - if err = os.WriteFile(TestDirPath+"parse_md/html_got_output.html", []byte(body_got), 0666); err != nil { + bodyWant, err := os.ReadFile(TestDirPath + "parse_md/html_want_output.html") + if err = os.WriteFile(TestDirPath+"parse_md/html_got_output.html", []byte(bodyGot), 0666); err != nil { t.Errorf("%v", err) } - if string(body_want) != body_got { + if string(bodyWant) != bodyGot { t.Errorf("%v\nThe expected and generated html can be found in test/", err) } } @@ -106,18 +106,18 @@ func TestParseMarkdownContent(t *testing.T) { t.Errorf("%v", err) } - frontmatter_got, _, _, parseSuccess := p.ParseMarkdownContent(string(inputMd)) + frontmatterGot, _, _, parseSuccess := p.ParseMarkdownContent(string(inputMd)) if !parseSuccess { - frontmatter_want := parser.Frontmatter{ + frontmatterWant := parser.Frontmatter{ Title: "Markdown Test", Date: "2024-03-23", Description: "File containing markdown to test the SSG", Type: "post", } - if !reflect.DeepEqual(frontmatter_got, frontmatter_want) { - t.Errorf("got %v, \nwant %v", frontmatter_got, frontmatter_want) + if !reflect.DeepEqual(frontmatterGot, frontmatterWant) { + t.Errorf("got %v, \nwant %v", frontmatterGot, frontmatterWant) } } }) @@ -125,110 +125,111 @@ func TestParseMarkdownContent(t *testing.T) { func TestParseConfig(t *testing.T) { t.Run("unmarshal `config.yml` to LayoutConfig", func(t *testing.T) { - got_parser := parser.Parser{ + gotParser := parser.Parser{ Templates: make(map[template.URL]parser.TemplateData), TagsMap: make(map[template.URL][]parser.TemplateData), ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), } - want_layout := parser.LayoutConfig{ + wantLayout := parser.LayoutConfig{ Navbar: []string{"index", "docs", "tags", "posts"}, BaseURL: "example.org", SiteTitle: "ssg", Author: "Anna", } - got_parser.ParseConfig(TestDirPath + "layout/config.yml") + gotParser.ParseConfig(TestDirPath + "layout/config.yml") - if !reflect.DeepEqual(got_parser.LayoutConfig, want_layout) { - t.Errorf("got \n%v want \n%v", got_parser.LayoutConfig, want_layout) + if !reflect.DeepEqual(gotParser.LayoutConfig, wantLayout) { + t.Errorf("got \n%v want \n%v", gotParser.LayoutConfig, wantLayout) } }) } func TestParseRobots(t *testing.T) { t.Run("parse and render `robots.txt`", func(t *testing.T) { - parser := parser.Parser{ + testParser := parser.Parser{ Templates: make(map[template.URL]parser.TemplateData), TagsMap: make(map[template.URL][]parser.TemplateData), ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), } - parser.LayoutConfig.BaseURL = "example.org" + testParser.LayoutConfig.BaseURL = "example.org" - parser.ParseRobots(TestDirPath+"layout/robots_txt/robots.txt", TestDirPath+"layout/robots_txt/got_robots.txt") + testParser.ParseRobots(TestDirPath+"layout/robots_txt/robots.txt", TestDirPath+"layout/robots_txt/got_robots.txt") - got_robots_txt, err := os.ReadFile(TestDirPath + "layout/robots_txt/got_robots.txt") + gotRobotsTxt, err := os.ReadFile(TestDirPath + "layout/robots_txt/got_robots.txt") if err != nil { t.Errorf("%v", err) } - want_robots_txt, err := os.ReadFile(TestDirPath + "layout/robots_txt/want_robots.txt") + wantRobotsTxt, err := os.ReadFile(TestDirPath + "layout/robots_txt/want_robots.txt") if err != nil { t.Errorf("%v", err) } - if !slices.Equal(got_robots_txt, want_robots_txt) { + if !slices.Equal(gotRobotsTxt, wantRobotsTxt) { t.Errorf("The expected and generated robots.txt can be found in test/layout/robots_txt/") } }) } -// func TestParseBacklink(t *testing.T) { - -// got_parser := parser.Parser{ -// Notes: make(map[template.URL]parser.Note), -// ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), -// } - -// // creating dummy notes for testing - -// got_parser.Notes[template.URL("notes/test/test.md")] = parser.Note{ -// Frontmatter: parser.Frontmatter{ -// Title: "head note", -// Type: "note", -// Head: true, -// }, -// Body: template.HTML("This is a [[backlink]]"), -// } - -// got_parser.Notes[template.URL("notes/test/backlink.md")] = parser.Note{ -// Frontmatter: parser.Frontmatter{ -// Title: "backlink", -// Type: "note", -// }, -// Body: template.HTML("Content of note."), -// } - -// t.Run("testing backlink parsing in body of markdown files", func(t *testing.T) { - -// got_parser.ParseBacklink("notes/test/test.md") - -// want_parser := parser.Parser{ -// Notes: map[template.URL]parser.Note{ -// template.URL("notes/test/test.md"): parser.Note{ -// Frontmatter: parser.Frontmatter{ -// Title: "head note", -// Type: "note", -// Head: true, -// }, -// Body: template.HTML("This is a [[backlink]] here"), -// LinkedNoteURLs: []template.URL{"notes/test/backlink.md"}, -// }, - -// template.URL("notes/test/backlink.md"): parser.Note{ -// Frontmatter: parser.Frontmatter{ -// Title: "backlink", -// Type: "note", -// }, -// Body: template.HTML("Content of note."), -// }, -// }, -// ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), -// } - -// got_list := got_parser.Notes["notes/test/test.md"].LinkedNoteURLs -// want_list := want_parser.Notes["notes/test/test.md"].LinkedNoteURLs - -// if !slices.Equal(got_list, want_list) { -// t.Errorf("got %v, want %v", got_list, want_list) -// } -// }) -// } +func TestNotesAndBacklinkParsing(t *testing.T) { + + gotParser := parser.Parser{ + Notes: make(map[template.URL]parser.Note), + ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), + } + + // creating dummy notes for testing + + gotParser.Notes["notes/test/test.md"] = parser.Note{ + CompleteURL: "notes/test/test.md", + Frontmatter: parser.Frontmatter{ + Title: "head note", + Type: "note", + Head: true, + }, + Body: "This is a [[backlink]] here", + } + + gotParser.Notes["notes/test/backlink.md"] = parser.Note{ + CompleteURL: "notes/test/backlink.md", + Frontmatter: parser.Frontmatter{ + Title: "backlink", + Type: "note", + }, + Body: "Content of note.", + } + + t.Run("testing notes and backlink parsing", func(t *testing.T) { + + gotParser.ParseBacklink("notes/test/test.md") + + wantParser := parser.Parser{ + Notes: map[template.URL]parser.Note{ + "notes/test/test.md": { + CompleteURL: template.URL("notes/test/test.md"), + Frontmatter: parser.Frontmatter{ + Title: "head note", + Type: "note", + Head: true, + }, + Body: template.HTML("This is a backlink here"), + LinkedNoteURLs: []template.URL{"notes/test/backlink.md"}, + }, + + "notes/test/backlink.md": { + CompleteURL: template.URL("notes/test/backlink.md"), + Frontmatter: parser.Frontmatter{ + Title: "backlink", + Type: "note", + }, + Body: template.HTML("Content of note."), + }, + }, + ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), + } + + if !reflect.DeepEqual(gotParser.Notes, wantParser.Notes) { + t.Errorf("got %v,\n want %v", gotParser.Notes, wantParser.Notes) + } + }) +} diff --git a/pkg/parser/zettel_parser.go b/pkg/parser/zettel_parser.go index 50aff08..4cb4cb9 100644 --- a/pkg/parser/zettel_parser.go +++ b/pkg/parser/zettel_parser.go @@ -81,9 +81,6 @@ func (p *Parser) BackLinkParser() { func (p *Parser) ParseBacklink(noteURL template.URL) { note := p.Notes[noteURL] noteBody := string(note.Body) // template.HTML -> string - // noteParentDir := note.CompleteURL - - // fmt.Println("Finding links for :", noteParentDir) backlinks := backlinkRE.FindAllString(noteBody, -1) @@ -101,7 +98,6 @@ func (p *Parser) ParseBacklink(noteURL template.URL) { anchorReference := fmt.Sprintf(`%s`, referenceCompleteURL, noteTitle) noteBody = strings.ReplaceAll(noteBody, backlink, anchorReference) - // fmt.Println(note.LinkedNoteURLs) note.LinkedNoteURLs = append(note.LinkedNoteURLs, referenceCompleteURL) } } @@ -114,7 +110,6 @@ func (p *Parser) ParseBacklink(noteURL template.URL) { MarkdownBody: note.MarkdownBody, LinkedNoteURLs: note.LinkedNoteURLs, } - // fmt.Println(p.Notes[noteURL]) } func (p *Parser) ValidateBackLink(noteTitle string) (template.URL, error) { From 432aec3720f8b6e8691b084c9771b999807343ed Mon Sep 17 00:00:00 2001 From: Anirudh Sudhir Date: Wed, 1 May 2024 12:55:47 +0530 Subject: [PATCH 3/3] refactor: improve error handling and use camelCase --- cmd/anna/livereload.go | 5 ++- cmd/anna/validate_html.go | 7 ++- cmd/anna/wizard.go | 10 ++++- main.go | 4 +- pkg/engine/anna_engine.go | 33 +++++++++++--- pkg/engine/anna_engine_test.go | 62 +++++++++++++-------------- pkg/engine/engine.go | 5 ++- pkg/engine/engine_integration_test.go | 32 +++++++------- pkg/engine/engine_test.go | 28 +++++------- pkg/engine/user_engine_test.go | 18 ++++---- pkg/helpers/helper.go | 27 +++++++++--- pkg/helpers/helper_test.go | 23 +++++----- pkg/parser/parser.go | 22 +++++++--- pkg/parser/parser_integration_test.go | 16 +++---- 14 files changed, 175 insertions(+), 117 deletions(-) diff --git a/cmd/anna/livereload.go b/cmd/anna/livereload.go index 9b473d8..a230d5d 100644 --- a/cmd/anna/livereload.go +++ b/cmd/anna/livereload.go @@ -132,7 +132,10 @@ func eventsHandler(w http.ResponseWriter, r *http.Request) { } event := "event:\ndata:\n\n" - w.Write([]byte(event)) + _, err := w.Write([]byte(event)) + if err != nil { + log.Fatal(err) + } w.(http.Flusher).Flush() countRequests.Store(countRequests.Load() - 1) diff --git a/cmd/anna/validate_html.go b/cmd/anna/validate_html.go index a1f604c..bd7a13f 100644 --- a/cmd/anna/validate_html.go +++ b/cmd/anna/validate_html.go @@ -47,7 +47,12 @@ func parseHTMLFile(path string) error { if err != nil { return err } - defer file.Close() + defer func() { + err = file.Close() + if err != nil { + log.Fatal(err) + } + }() // Load the HTML content into a GoQuery document doc, err := goquery.NewDocumentFromReader(file) diff --git a/cmd/anna/wizard.go b/cmd/anna/wizard.go index 6d03ce8..97b50c6 100644 --- a/cmd/anna/wizard.go +++ b/cmd/anna/wizard.go @@ -3,6 +3,7 @@ package anna import ( "context" "encoding/json" + "errors" "fmt" "log" "net/http" @@ -38,7 +39,7 @@ func (ws *WizardServer) Start() { fs := http.FileServer(http.Dir("./site/static/wizard")) http.Handle("/", fs) fmt.Printf("Wizard is running at: http://localhost%s\n", ws.server.Addr) - if err := ws.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + if err := ws.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("Could not start server: %v", err) } } @@ -76,7 +77,12 @@ func writeConfigToFile(config Config) error { if err != nil { return err } - defer file.Close() + defer func() { + err = file.Close() + if err != nil { + log.Fatal(err) + } + }() // Encode the config into YAML format and write it to the file. if err := yaml.NewEncoder(file).Encode(&config); err != nil { diff --git a/main.go b/main.go index a81d995..4b54fd5 100644 --- a/main.go +++ b/main.go @@ -52,7 +52,9 @@ func main() { server := anna.NewWizardServer(":8080") go server.Start() <-anna.FormSubmittedCh // wait for response - server.Stop() // stop the server + if err := server.Stop(); err != nil { + log.Println(err) + } annaCmd.VanillaRender() annaCmd.StartLiveReload() } diff --git a/pkg/engine/anna_engine.go b/pkg/engine/anna_engine.go index e68b093..1ecfb93 100644 --- a/pkg/engine/anna_engine.go +++ b/pkg/engine/anna_engine.go @@ -91,7 +91,7 @@ func (e *Engine) RenderTags(fileOutPath string, templ *template.Template) { go func(tag template.URL, taggedTemplates []parser.TemplateData) { defer wg.Done() - e.RenderPage(fileOutPath, template.URL(tag), templ, "tag-subpage") + e.RenderPage(fileOutPath, tag, templ, "tag-subpage") }(tag, taggedTemplates) } @@ -105,7 +105,12 @@ func (e *Engine) GenerateNoteJSONIdex(outFilePath string) { e.ErrorLogger.Fatal(err) } - defer jsonFile.Close() + defer func() { + err = jsonFile.Close() + if err != nil { + e.ErrorLogger.Fatal(err) + } + }() jsonMergedMarshaledData, err := json.Marshal(e.DeepDataMerge.Notes) if err != nil { @@ -127,7 +132,12 @@ func (e *Engine) GenerateJSONIndex(outFilePath string) { if err != nil { e.ErrorLogger.Fatal(err) } - defer jsonFile.Close() + defer func() { + err = jsonFile.Close() + if err != nil { + e.ErrorLogger.Fatal(err) + } + }() // Copying contents from e.Templates to new JsonMerged struct jsonIndexTemplate := make(map[template.URL]JSONIndexTemplate) @@ -186,7 +196,14 @@ func (e *Engine) GenerateSitemap(outFilePath string) { if err != nil { e.ErrorLogger.Fatal(err) } - defer outputFile.Close() + + defer func() { + err = outputFile.Close() + if err != nil { + e.ErrorLogger.Fatal(err) + } + }() + _, err = outputFile.Write(buffer.Bytes()) if err != nil { e.ErrorLogger.Fatal(err) @@ -220,7 +237,13 @@ func (e *Engine) GenerateFeed() { if err != nil { e.ErrorLogger.Fatal(err) } - defer outputFile.Close() + defer func() { + err = outputFile.Close() + if err != nil { + e.ErrorLogger.Fatal(err) + } + }() + _, err = outputFile.Write(buffer.Bytes()) if err != nil { e.ErrorLogger.Fatal(err) diff --git a/pkg/engine/anna_engine_test.go b/pkg/engine/anna_engine_test.go index c789fcf..0c491e6 100644 --- a/pkg/engine/anna_engine_test.go +++ b/pkg/engine/anna_engine_test.go @@ -67,47 +67,47 @@ func TestRenderTags(t *testing.T) { e.RenderTags(fileOutPath, templ) t.Run("render tag.html", func(t *testing.T) { - got_tags_file, err := os.ReadFile(TestDirPath + "render_tags/rendered/tags.html") + gotTagsFile, err := os.ReadFile(TestDirPath + "render_tags/rendered/tags.html") if err != nil { t.Errorf("%v", err) } - want_tags_file, err := os.ReadFile(TestDirPath + "render_tags/want_tags.html") + wantTagsFile, err := os.ReadFile(TestDirPath + "render_tags/want_tags.html") if err != nil { t.Errorf("%v", err) } - if !slices.Equal(got_tags_file, want_tags_file) { + if !slices.Equal(gotTagsFile, wantTagsFile) { t.Errorf("The expected and generated tags.html can be found in test/engine/render_tags/rendered/") } }) t.Run("render tag-subpage.html", func(t *testing.T) { - got_blogs_file, err := os.ReadFile(TestDirPath + "render_tags/rendered/tags/blogs.html") + gotBlogsFile, err := os.ReadFile(TestDirPath + "render_tags/rendered/tags/blogs.html") if err != nil { t.Errorf("%v", err) } - want_blogs_file, err := os.ReadFile(TestDirPath + "render_tags/want_blogs_tags.html") + wantBlogsFile, err := os.ReadFile(TestDirPath + "render_tags/want_blogs_tags.html") if err != nil { t.Errorf("%v", err) } - if !slices.Equal(got_blogs_file, want_blogs_file) { + if !slices.Equal(gotBlogsFile, wantBlogsFile) { t.Errorf("The expected and generated blogs.html tag-subpage can be found in test/engine/render_tags/rendered/tags/") } - got_tech_file, err := os.ReadFile(TestDirPath + "render_tags/rendered/tags/tech.html") + gotTechFile, err := os.ReadFile(TestDirPath + "render_tags/rendered/tags/tech.html") if err != nil { t.Errorf("%v", err) } - want_tech_file, err := os.ReadFile(TestDirPath + "render_tags/want_tech_tags.html") + wantTechFile, err := os.ReadFile(TestDirPath + "render_tags/want_tech_tags.html") if err != nil { t.Errorf("%v", err) } - if !slices.Equal(got_tech_file, want_tech_file) { + if !slices.Equal(gotTechFile, wantTechFile) { t.Errorf("The expected and generated tech.html tag-subpage can be found in test/engine/render_tags/rendered/tags/") } }) @@ -134,20 +134,20 @@ func TestGenerateMergedJson(t *testing.T) { e.GenerateJSONIndex(TestDirPath + "json_index_test/") - got_json, err := os.ReadFile(TestDirPath + "/json_index_test/rendered/static/index.json") + gotJson, err := os.ReadFile(TestDirPath + "/json_index_test/rendered/static/index.json") if err != nil { t.Errorf("%v", err) } - want_json, err := os.ReadFile(TestDirPath + "/json_index_test/want_index.json") + wantJson, err := os.ReadFile(TestDirPath + "/json_index_test/want_index.json") if err != nil { t.Errorf("%v", err) } - got_json = bytes.TrimSpace(got_json) - want_json = bytes.TrimSpace(want_json) + gotJson = bytes.TrimSpace(gotJson) + wantJson = bytes.TrimSpace(wantJson) - if !slices.Equal(got_json, want_json) { + if !slices.Equal(gotJson, wantJson) { t.Errorf("The expected and generated json can be found in test/engine/json_index_test") } }) @@ -155,11 +155,11 @@ func TestGenerateMergedJson(t *testing.T) { func TestGenerateSitemap(t *testing.T) { t.Run("render sitemap.xml", func(t *testing.T) { - engine := engine.Engine{ + testEngine := engine.Engine{ ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), } - engine.DeepDataMerge.Templates = make(map[template.URL]parser.TemplateData) - engine.DeepDataMerge.TagsMap = make(map[template.URL][]parser.TemplateData) + testEngine.DeepDataMerge.Templates = make(map[template.URL]parser.TemplateData) + testEngine.DeepDataMerge.TagsMap = make(map[template.URL][]parser.TemplateData) t1 := parser.TemplateData{ CompleteURL: "index.html", @@ -182,35 +182,35 @@ func TestGenerateSitemap(t *testing.T) { }, } - engine.DeepDataMerge.LayoutConfig.BaseURL = "example.org" - // setting up engine - engine.DeepDataMerge.Templates["index"] = t1 - engine.DeepDataMerge.Templates["about"] = t2 - engine.DeepDataMerge.Templates["research"] = t3 + testEngine.DeepDataMerge.LayoutConfig.BaseURL = "example.org" + // setting up testEngine + testEngine.DeepDataMerge.Templates["index"] = t1 + testEngine.DeepDataMerge.Templates["about"] = t2 + testEngine.DeepDataMerge.Templates["research"] = t3 - engine.GenerateSitemap(TestDirPath + "sitemap/got_sitemap.xml") + testEngine.GenerateSitemap(TestDirPath + "sitemap/got_sitemap.xml") - got_sitemap, err := os.ReadFile(TestDirPath + "sitemap/got_sitemap.xml") + gotSitemap, err := os.ReadFile(TestDirPath + "sitemap/got_sitemap.xml") if err != nil { t.Errorf("Error in reading the contents of got_sitemap.xml") } - want_sitemap, err := os.ReadFile(TestDirPath + "sitemap/want_sitemap.xml") + wantSitemap, err := os.ReadFile(TestDirPath + "sitemap/want_sitemap.xml") if err != nil { t.Errorf("Error in reading the contents of _sitemap.xml") } - got_sitemap_string := string(got_sitemap) - want_sitemap_string := string(want_sitemap) - got_sitemap_string = strings.TrimFunc(got_sitemap_string, func(r rune) bool { + gotSitemapString := string(gotSitemap) + wantSitemapString := string(wantSitemap) + gotSitemapString = strings.TrimFunc(gotSitemapString, func(r rune) bool { return r == '\n' || r == '\t' || r == ' ' }) - want_sitemap_string = strings.TrimFunc(want_sitemap_string, func(r rune) bool { + wantSitemapString = strings.TrimFunc(wantSitemapString, func(r rune) bool { return r == '\n' || r == '\t' || r == ' ' }) - if strings.Compare(got_sitemap_string, want_sitemap_string) == 0 { - t.Errorf("The expected and generated sitemap can be found in test/engine/sitemap/") + if strings.Compare(gotSitemapString, wantSitemapString) == 0 { + t.Errorf("The expected and generated sitemap can be found in test/testEngine/sitemap/") } }) } diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index ab46ec4..19b3164 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -10,7 +10,7 @@ import ( "github.com/acmpesuecc/anna/pkg/parser" ) -// This struct holds all of the ssg data +// DeepDataMerge This struct holds all the ssg data type DeepDataMerge struct { // Templates stores the template data of all the pages of the site // Access the data for a particular page by using the relative path to the file as the key @@ -52,7 +52,7 @@ type PageData struct { PageURL template.URL } -// This structure is solely used for storing the JSON index +// JSONIndexTemplate This structure is solely used for storing the JSON index type JSONIndexTemplate struct { CompleteURL template.URL Frontmatter parser.Frontmatter @@ -60,6 +60,7 @@ type JSONIndexTemplate struct { } /* +RenderPage fileOutPath - stores the parent directory to store rendered files, usually `site/` pagePath - stores the path to write the given page without the prefix directory diff --git a/pkg/engine/engine_integration_test.go b/pkg/engine/engine_integration_test.go index a1e7b2a..911c4c4 100644 --- a/pkg/engine/engine_integration_test.go +++ b/pkg/engine/engine_integration_test.go @@ -12,20 +12,20 @@ import ( ) func TestRenderUserDefinedPages(t *testing.T) { - engine := engine.Engine{ + testEngine := engine.Engine{ ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), } - engine.DeepDataMerge.Templates = make(map[template.URL]parser.TemplateData) - engine.DeepDataMerge.TagsMap = make(map[template.URL][]parser.TemplateData) + testEngine.DeepDataMerge.Templates = make(map[template.URL]parser.TemplateData) + testEngine.DeepDataMerge.TagsMap = make(map[template.URL][]parser.TemplateData) - engine.DeepDataMerge.Templates["index.html"] = + testEngine.DeepDataMerge.Templates["index.html"] = parser.TemplateData{ - Body: template.HTML("

Index Page

"), + Body: "

Index Page

", CompleteURL: "index.html", } - engine.DeepDataMerge.Templates["posts/hello.html"] = parser.TemplateData{ - Body: template.HTML("

Hello World

"), + testEngine.DeepDataMerge.Templates["posts/hello.html"] = parser.TemplateData{ + Body: "

Hello World

", CompleteURL: "posts/hello.html", } @@ -40,34 +40,34 @@ func TestRenderUserDefinedPages(t *testing.T) { t.Errorf("%v", err) } - engine.RenderUserDefinedPages(TestDirPath+"render_user_defined/", templ) + testEngine.RenderUserDefinedPages(TestDirPath+"render_user_defined/", templ) - want_index_file, err := os.ReadFile(TestDirPath + "render_user_defined/want_index.html") + wantIndexFile, err := os.ReadFile(TestDirPath + "render_user_defined/want_index.html") if err != nil { t.Errorf("%v", err) } - got_index_file, err := os.ReadFile(TestDirPath + "render_user_defined/rendered/index.html") + gotIndexFile, err := os.ReadFile(TestDirPath + "render_user_defined/rendered/index.html") if err != nil { t.Errorf("%v", err) } - if !slices.Equal(want_index_file, got_index_file) { - t.Errorf("The expected and generated index.html can be found in test/engine/render_user_defined/rendered/") + if !slices.Equal(wantIndexFile, gotIndexFile) { + t.Errorf("The expected and generated index.html can be found in test/testEngine/render_user_defined/rendered/") } - want_post_hello, err := os.ReadFile(TestDirPath + "render_user_defined/want_post_hello.html") + wantPostHello, err := os.ReadFile(TestDirPath + "render_user_defined/want_post_hello.html") if err != nil { t.Errorf("%v", err) } - got_post_hello, err := os.ReadFile(TestDirPath + "render_user_defined/rendered/posts/hello.html") + gotPostHello, err := os.ReadFile(TestDirPath + "render_user_defined/rendered/posts/hello.html") if err != nil { t.Errorf("%v", err) } - if !slices.Equal(want_post_hello, got_post_hello) { - t.Errorf("The expected and generated post/hello.html can be found in test/engine/render_user_defined/rendered/posts/") + if !slices.Equal(wantPostHello, gotPostHello) { + t.Errorf("The expected and generated post/hello.html can be found in test/testEngine/render_user_defined/rendered/posts/") } }) diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index a17e4cd..aa24d49 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -19,14 +19,14 @@ func TestRenderPage(t *testing.T) { } t.Run("render a single page while creating a new directory", func(t *testing.T) { - engine := engine.Engine{ + testEngine := engine.Engine{ ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), } - engine.DeepDataMerge.Templates = make(map[template.URL]parser.TemplateData) - engine.DeepDataMerge.TagsMap = make(map[template.URL][]parser.TemplateData) + testEngine.DeepDataMerge.Templates = make(map[template.URL]parser.TemplateData) + testEngine.DeepDataMerge.TagsMap = make(map[template.URL][]parser.TemplateData) - engine.DeepDataMerge.Templates["posts/got.html"] = parser.TemplateData{ - CompleteURL: template.URL("got.html"), + testEngine.DeepDataMerge.Templates["posts/got.html"] = parser.TemplateData{ + CompleteURL: "got.html", Frontmatter: parser.Frontmatter{ Title: "Hello", Date: "2024-03-28", @@ -35,13 +35,7 @@ func TestRenderPage(t *testing.T) { Description: "Index page of site", Tags: []string{"blog", "thoughts"}, }, - Body: template.HTML("

Hello World

"), - // Layout: parser.LayoutConfig{ - // Navbar: []string{"index", "posts"}, - // BaseURL: "https://example.org", - // SiteTitle: "Anna", - // Author: "anna", - // }, + Body: "

Hello World

", } templ, err := template.ParseFiles(TestDirPath + "render_page/template_input.html") @@ -49,20 +43,20 @@ func TestRenderPage(t *testing.T) { t.Errorf("%v", err) } - engine.RenderPage(TestDirPath+"render_page/", "posts/got.html", templ, "page") + testEngine.RenderPage(TestDirPath+"render_page/", "posts/got.html", templ, "page") - got_file, err := os.ReadFile(TestDirPath + "render_page/rendered/posts/got.html") + gotFile, err := os.ReadFile(TestDirPath + "render_page/rendered/posts/got.html") if err != nil { t.Errorf("%v", err) } - want_file, err := os.ReadFile(TestDirPath + "render_page/want.html") + wantFile, err := os.ReadFile(TestDirPath + "render_page/want.html") if err != nil { t.Errorf("%v", err) } - if !slices.Equal(got_file, want_file) { - t.Errorf("The expected and generated page.html can be found in test/engine/render_page/rendered/") + if !slices.Equal(gotFile, wantFile) { + t.Errorf("The expected and generated page.html can be found in test/testEngine/render_page/rendered/") } }) diff --git a/pkg/engine/user_engine_test.go b/pkg/engine/user_engine_test.go index 9aa5e40..d5be989 100644 --- a/pkg/engine/user_engine_test.go +++ b/pkg/engine/user_engine_test.go @@ -13,13 +13,13 @@ import ( func TestRenderEngineGeneratedFiles(t *testing.T) { - engine := engine.Engine{ + testEngine := engine.Engine{ ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), } - engine.DeepDataMerge.Templates = make(map[template.URL]parser.TemplateData) - engine.DeepDataMerge.TagsMap = make(map[template.URL][]parser.TemplateData) + testEngine.DeepDataMerge.Templates = make(map[template.URL]parser.TemplateData) + testEngine.DeepDataMerge.TagsMap = make(map[template.URL][]parser.TemplateData) - engine.DeepDataMerge.Posts = []parser.TemplateData{ + testEngine.DeepDataMerge.Posts = []parser.TemplateData{ { CompleteURL: "posts/file1.html", Frontmatter: parser.Frontmatter{ @@ -58,20 +58,20 @@ func TestRenderEngineGeneratedFiles(t *testing.T) { t.Errorf("%v", err) } - engine.RenderEngineGeneratedFiles(TestDirPath+"render_engine_generated/", templ) + testEngine.RenderEngineGeneratedFiles(TestDirPath+"render_engine_generated/", templ) - want_posts_file, err := os.ReadFile(TestDirPath + "render_engine_generated/want_posts.html") + wantPostsFile, err := os.ReadFile(TestDirPath + "render_engine_generated/want_posts.html") if err != nil { t.Errorf("%v", err) } - got_posts_file, err := os.ReadFile(TestDirPath + "render_engine_generated/rendered/posts.html") + gotPostsFile, err := os.ReadFile(TestDirPath + "render_engine_generated/rendered/posts.html") if err != nil { t.Errorf("%v", err) } - if !slices.Equal(want_posts_file, got_posts_file) { - t.Errorf("The expected and generated posts.html can be found in test/engine/render_engine_generated/rendered/") + if !slices.Equal(wantPostsFile, gotPostsFile) { + t.Errorf("The expected and generated posts.html can be found in test/testEngine/render_engine_generated/rendered/") } }) } diff --git a/pkg/helpers/helper.go b/pkg/helpers/helper.go index 379ff37..50cf994 100644 --- a/pkg/helpers/helper.go +++ b/pkg/helpers/helper.go @@ -9,13 +9,16 @@ import ( const SiteDataPath string = "site/" -var version string = "2.0.0" // use variable +var version = "2.0.0" // use variable type Helper struct { ErrorLogger *log.Logger } -// Copies the contents of the dirPath directory to outDirPath +/* +CopyDirectoryContents +Copies the contents of the dirPath directory to outDirPath +*/ func (h *Helper) CopyDirectoryContents(dirPath string, outDirPath string) { dirEntries, err := os.ReadDir(dirPath) if err != nil { @@ -42,14 +45,19 @@ func (h *Helper) CopyFiles(srcPath string, destPath string) { if err != nil { h.ErrorLogger.Fatal(err) } - defer source.Close() + defer func() { + err = source.Close() + if err != nil { + h.ErrorLogger.Fatal(err) + } + }() // Creating subdirectories if the filepath contains '/' - if strings.Contains(string(destPath), "/") { + if strings.Contains(destPath, "/") { // Extracting the directory path from the page path - splitPaths := strings.Split(string(destPath), "/") + splitPaths := strings.Split(destPath, "/") filename := splitPaths[len(splitPaths)-1] - pagePathWithoutFilename, _ := strings.CutSuffix(string(destPath), filename) + pagePathWithoutFilename, _ := strings.CutSuffix(destPath, filename) err := os.MkdirAll(pagePathWithoutFilename, 0750) if err != nil { @@ -61,7 +69,12 @@ func (h *Helper) CopyFiles(srcPath string, destPath string) { if err != nil { h.ErrorLogger.Fatal(err) } - defer destination.Close() + defer func() { + err = destination.Close() + if err != nil { + h.ErrorLogger.Fatal(err) + } + }() _, err = io.Copy(destination, source) if err != nil { diff --git a/pkg/helpers/helper_test.go b/pkg/helpers/helper_test.go index 68529f8..f590019 100644 --- a/pkg/helpers/helper_test.go +++ b/pkg/helpers/helper_test.go @@ -20,31 +20,34 @@ func TestCopyDirectoryContents(t *testing.T) { helper.CopyDirectoryContents(HelperTestDirPath+"copy_dir/", HelperTestDirPath+"copy_dir/rendered/") baseDirFS := os.DirFS(HelperTestDirPath + "copy_dir/input_dir/") - TraverseDirectory(baseDirFS, t) + err := testfuncTraverseDirectory(baseDirFS, t) + if err != nil { + t.Error(err) + } }) } -func TraverseDirectory(baseDirFS fs.FS, t *testing.T) error { - fs.WalkDir(baseDirFS, ".", func(path string, dir fs.DirEntry, err error) error { +func testfuncTraverseDirectory(baseDirFS fs.FS, t *testing.T) error { + err := fs.WalkDir(baseDirFS, ".", func(path string, dir fs.DirEntry, err error) error { if !dir.IsDir() { - got_file, err := os.ReadFile(HelperTestDirPath + "copy_dir/input_dir/" + path) + gotFile, err := os.ReadFile(HelperTestDirPath + "copy_dir/input_dir/" + path) if err != nil { t.Errorf("%v", err) } - want_file, err := os.ReadFile(HelperTestDirPath + "copy_dir/rendered/input_dir/" + path) + wantFile, err := os.ReadFile(HelperTestDirPath + "copy_dir/rendered/input_dir/" + path) if err != nil { t.Errorf("%v", err) } - if !slices.Equal(got_file, want_file) { + if !slices.Equal(gotFile, wantFile) { t.Errorf("The expected and generated files can be found in %s", HelperTestDirPath) } } return nil }) - return nil + return err } func TestCopyFiles(t *testing.T) { @@ -54,17 +57,17 @@ func TestCopyFiles(t *testing.T) { } helper.CopyFiles(HelperTestDirPath+"copy_files/input.txt", HelperTestDirPath+"copy_files/rendered/output.txt") - got_file, err := os.ReadFile(HelperTestDirPath + "copy_files/input.txt") + gotFile, err := os.ReadFile(HelperTestDirPath + "copy_files/input.txt") if err != nil { t.Errorf("%v", err) } - want_file, err := os.ReadFile(HelperTestDirPath + "copy_files/rendered/output.txt") + wantFile, err := os.ReadFile(HelperTestDirPath + "copy_files/rendered/output.txt") if err != nil { t.Errorf("%v", err) } - if !slices.Equal(got_file, want_file) { + if !slices.Equal(gotFile, wantFile) { t.Errorf("The expected and generated files can be found in %s", HelperTestDirPath) } }) diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index 27870da..ebd538a 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -49,7 +49,7 @@ type Frontmatter struct { Head bool `yaml:"head"` } -// This struct holds all of the data required to render any page of the site +// TemplateData This struct holds all of the data required to render any page of the site type TemplateData struct { CompleteURL template.URL Date int64 @@ -97,7 +97,7 @@ func (p *Parser) ParseMDDir(baseDirPath string, baseDirFS fs.FS) { helper := helpers.Helper{ ErrorLogger: p.ErrorLogger, } - fs.WalkDir(baseDirFS, ".", func(path string, dir fs.DirEntry, err error) error { + err := fs.WalkDir(baseDirFS, ".", func(path string, dir fs.DirEntry, err error) error { if path != "." && path != ".obsidian" { if dir.IsDir() { subDir := os.DirFS(path) @@ -127,12 +127,15 @@ func (p *Parser) ParseMDDir(baseDirPath string, baseDirFS fs.FS) { } return nil }) + if err != nil { + helper.ErrorLogger.Fatal(err) + } } func (p *Parser) AddFile(baseDirPath string, dirEntryPath string, frontmatter Frontmatter, markdownContent string, body string) { p.MdFilesName = append(p.MdFilesName, dirEntryPath) - filepath := baseDirPath + dirEntryPath - p.MdFilesPath = append(p.MdFilesPath, filepath) + testFilepath := baseDirPath + dirEntryPath + p.MdFilesPath = append(p.MdFilesPath, testFilepath) var date int64 if frontmatter.Date != "" { @@ -141,7 +144,7 @@ func (p *Parser) AddFile(baseDirPath string, dirEntryPath string, frontmatter Fr date = 0 } - key, _ := strings.CutPrefix(filepath, helpers.SiteDataPath+"content/") + key, _ := strings.CutPrefix(testFilepath, helpers.SiteDataPath+"content/") url, _ := strings.CutSuffix(key, ".md") url += ".html" @@ -328,7 +331,12 @@ func (p *Parser) ParseRobots(inFilePath string, outFilePath string) { if err != nil { p.ErrorLogger.Fatal(err) } - defer outputFile.Close() + defer func() { + err = outputFile.Close() + if err != nil { + p.ErrorLogger.Fatal(err) + } + }() _, err = outputFile.Write(buffer.Bytes()) if err != nil { @@ -336,7 +344,7 @@ func (p *Parser) ParseRobots(inFilePath string, outFilePath string) { } } -// Parse all the ".html" layout files in the layout/ directory +// ParseLayoutFiles Parse all the ".html" layout files in the layout/ directory func (p *Parser) ParseLayoutFiles() *template.Template { // Parsing all files in the layout/ dir which match the "*.html" pattern templ, err := template.ParseGlob(helpers.SiteDataPath + "layout/*.html") diff --git a/pkg/parser/parser_integration_test.go b/pkg/parser/parser_integration_test.go index bbbb40e..78059fd 100644 --- a/pkg/parser/parser_integration_test.go +++ b/pkg/parser/parser_integration_test.go @@ -21,11 +21,11 @@ func TestParseMDDir(t *testing.T) { TestDirFS := os.DirFS(TestDirPath + "input") p.ParseMDDir(TestDirPath+"input/", TestDirFS) - got_parsed_files := len(p.MdFilesName) - want_parsed_files := 1 + gotParsedFiles := len(p.MdFilesName) + wantParsedFiles := 1 - if got_parsed_files != want_parsed_files { - t.Errorf("got %v, want %v", got_parsed_files, want_parsed_files) + if gotParsedFiles != wantParsedFiles { + t.Errorf("got %v, want %v", gotParsedFiles, wantParsedFiles) } }) @@ -41,10 +41,10 @@ func TestParseMDDir(t *testing.T) { inpBaseDirFS := os.DirFS(TestDirPath + "input") p.ParseMDDir(TestDirPath+"input/", inpBaseDirFS) - got_parsed_files := len(p.MdFilesName) - want_parsed_files := 2 - if got_parsed_files != want_parsed_files { - t.Errorf("got %v, want %v", got_parsed_files, want_parsed_files) + gotParsedFiles := len(p.MdFilesName) + wantParsedFiles := 2 + if gotParsedFiles != wantParsedFiles { + t.Errorf("got %v, want %v", gotParsedFiles, wantParsedFiles) } }) }