169 lines
4.0 KiB
Go

package build
import (
"bytes"
"gopkg.in/yaml.v2"
"os"
"path/filepath"
"strings"
"text/template"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
)
type Docs struct {
PackageJSONPath string
DestinationPath string
LayoutsPath string
PartialsPath string
PagesPath string
StaticAssetsPath string
}
type FrontMatter struct {
Layout string `yaml:"layout"`
Title string `yaml:"title"`
Description string `yaml:"description"`
}
func (receiver Docs) Build() error {
// Read Markdown files from PagesPath
files, err := os.ReadDir(receiver.PagesPath)
if err != nil {
return err
}
pgkJSON, _ := readPackageJSON(receiver.PackageJSONPath)
version := pgkJSON.Version
for _, file := range files {
if strings.HasSuffix(file.Name(), ".md") {
content, err := os.ReadFile(filepath.Join(receiver.PagesPath, file.Name()))
if err != nil {
return err
}
// Parse front matter
frontMatter, markdownContent := parseFrontMatter(content)
// Load and parse the layout template with partials
tmpl, err := parseTemplateWithPartials(receiver.LayoutsPath, receiver.PartialsPath, frontMatter.Layout)
if err != nil {
return err
}
// Convert Markdown to HTML
renderer := html.NewRenderer(html.RendererOptions{})
htmlContent := markdown.ToHTML([]byte(markdownContent), nil, renderer)
// Execute the template with the HTML content
var buf bytes.Buffer
err = tmpl.Execute(&buf, map[string]interface{}{
"Content": string(htmlContent),
"FrontMatter": frontMatter,
"Version": version,
})
if err != nil {
return err
}
if file.Name() == "index.md" {
err = os.WriteFile(filepath.Join(receiver.DestinationPath, "index.html"), buf.Bytes(), 0644)
if err != nil {
return err
}
continue
} else {
// Create directory for the file
err = os.MkdirAll(filepath.Join(receiver.DestinationPath, strings.Replace(file.Name(), ".md", "", -1)), 0755)
if err != nil {
return err
}
// Write to the destination path
err = os.WriteFile(filepath.Join(receiver.DestinationPath, strings.Replace(file.Name(), ".md", "/index.html", -1)), buf.Bytes(), 0644)
if err != nil {
return err
}
}
}
}
// Copy static assets
err = copyDir(receiver.StaticAssetsPath, filepath.Join(receiver.DestinationPath))
return nil
}
func copyDir(sourcePath string, destinationPath string) error {
ensureDirectoryExists(destinationPath)
// Read source directory
files, err := os.ReadDir(sourcePath)
if err != nil {
return err
}
for _, file := range files {
if file.IsDir() {
// Recursively copy subdirectories
err = copyDir(filepath.Join(sourcePath, file.Name()), filepath.Join(destinationPath, file.Name()))
if err != nil {
return err
}
} else {
// Copy file
readFile, err := os.ReadFile(filepath.Join(sourcePath, file.Name()))
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(destinationPath, file.Name()), readFile, 0644)
if err != nil {
return err
}
}
}
return nil
}
func parseFrontMatter(content []byte) (FrontMatter, string) {
// Split the content by the end of the front matter (assuming it's delineated by '---')
parts := strings.SplitN(string(content), "---", 3)
var frontMatter FrontMatter
if len(parts) > 2 {
err := yaml.Unmarshal([]byte(parts[1]), &frontMatter)
if err != nil {
return FrontMatter{}, ""
}
return frontMatter, parts[2]
}
return frontMatter, string(content)
}
func parseTemplateWithPartials(layoutsPath, partialsPath, layoutName string) (*template.Template, error) {
// Parse main layout
mainLayoutPath := filepath.Join(layoutsPath, layoutName+".html")
tmpl, err := template.ParseFiles(mainLayoutPath)
if err != nil {
return nil, err
}
// Parse partials
partials, err := os.ReadDir(partialsPath)
if err != nil {
return nil, err
}
for _, partial := range partials {
_, err := tmpl.ParseFiles(filepath.Join(partialsPath, partial.Name()))
if err != nil {
return nil, err
}
}
return tmpl, nil
}