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 `