diff --git a/docs/cmd/ssg.go b/docs/cmd/ssg.go index 94584e4..24e84a4 100644 --- a/docs/cmd/ssg.go +++ b/docs/cmd/ssg.go @@ -1,286 +1,18 @@ package main import ( - "bytes" - "fmt" - "html/template" - "os" - "path/filepath" - "strings" - - "github.com/alecthomas/chroma/formatters/html" - "github.com/yuin/goldmark" - highlighting "github.com/yuin/goldmark-highlighting" - meta "github.com/yuin/goldmark-meta" - "github.com/yuin/goldmark/extension" - "github.com/yuin/goldmark/parser" - ghtml "github.com/yuin/goldmark/renderer/html" - "go.abhg.dev/goldmark/anchor" + "github.com/picosh/pdocs" ) -type MetaData struct { - Title string - Description string - Slug string - Keywords []string - Template string -} - -type ParsedText struct { - Html template.HTML - *MetaData -} - -func toString(obj interface{}) string { - if obj == nil { - return "" - } - return obj.(string) -} - -func toKeywords(obj interface{}) ([]string, error) { - arr := make([]string, 0) - if obj == nil { - return arr, nil - } - - switch raw := obj.(type) { - case []interface{}: - for _, tag := range raw { - arr = append(arr, tag.(string)) - } - case string: - keywords := strings.Split(raw, " ") - for _, tag := range keywords { - arr = append(arr, strings.TrimSpace(tag)) - } - default: - return arr, fmt.Errorf("unsupported type for `keywords` variable: %T", raw) - } - - return arr, nil -} - -func parseMarkdown(text string) (*ParsedText, error) { - parsed := ParsedText{ - MetaData: &MetaData{ - Keywords: []string{}, - }, - } - var buf bytes.Buffer - hili := highlighting.NewHighlighting( - highlighting.WithFormatOptions( - html.WithLineNumbers(true), - html.WithClasses(true), - ), - ) - md := goldmark.New( - goldmark.WithExtensions( - extension.GFM, - extension.Footnote, - meta.Meta, - hili, - &anchor.Extender{ - Position: anchor.Before, - Texter: anchor.Text("#"), - }, - ), - goldmark.WithParserOptions( - parser.WithAutoHeadingID(), - ), - goldmark.WithRendererOptions( - ghtml.WithUnsafe(), - ), - ) - context := parser.NewContext() - if err := md.Convert([]byte(text), &buf, parser.WithContext(context)); err != nil { - return &parsed, err - } - parsed.Html = template.HTML(buf.String()) - - metaData := meta.Get(context) - parsed.Title = toString(metaData["title"]) - parsed.Description = toString(metaData["description"]) - parsed.Slug = toString(metaData["slug"]) - parsed.Template = toString(metaData["template"]) - - keywords, err := toKeywords(metaData["keywords"]) - if err != nil { - return &parsed, err - } - parsed.Keywords = keywords - - return &parsed, nil -} - -func walkDir(root string) ([]string, error) { - var files []string - err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if !info.IsDir() { - fmt.Println(path) - files = append(files, path) - } - return nil - }) - return files, err -} - -func renderTemplate(templates []string, tmpl string) (*template.Template, error) { - files := make([]string, len(templates)) - copy(files, templates) - files = append( - files, - tmpl, - ) - - ts, err := template.New("base").ParseFiles(files...) - if err != nil { - return nil, err - } - return ts, nil -} - -func page(dir string) func(p string) string { - return func(p string) string { - return filepath.Join(dir, p) - } -} - -// ============================================ - -type Page struct { - Page string - Data *ParsedText - Prev *Sitemap - Next *Sitemap - Sitemap []*Sitemap -} - -type DocConfig struct { - out string - tmpl string - sitemap []*Sitemap -} - -func (config *DocConfig) genPage(templates []string, page *Page) error { - tmpl := "post.page.tmpl" - if page.Data.Template != "" { - tmpl = page.Data.Template - } - - ts, err := renderTemplate(templates, filepath.Join(config.tmpl, tmpl)) - - if err != nil { - return err - } - - buf := new(bytes.Buffer) - err = ts.Execute(buf, page) - if err != nil { - return err - } - - base := filepath.Base(strings.ReplaceAll(page.Page, ".md", "")) - name := base - if page.Data.Slug != "" { - name = page.Data.Slug - } - - fp := filepath.Join( - config.out, - fmt.Sprintf("%s.html", name), - ) - err = os.WriteFile(fp, buf.Bytes(), 0644) - if err != nil { - return err - } - - return nil -} - -func (config *DocConfig) genSite() error { - tmpl, err := walkDir(config.tmpl) - if err != nil { - return err - } - - for _, toc := range config.sitemap { - for idx := range toc.Children { - toc.Children[idx].ParentHref = toc.Href - } - } - - for idx, toc := range config.sitemap { - if toc.Page == "" { - continue - } - - data, err := os.ReadFile(toc.Page) - if err != nil { - return err - } - d, err := parseMarkdown(string(data)) - if err != nil { - return err - } - - var prev *Sitemap - if idx > 0 { - prev = config.sitemap[idx-1] - } - var next *Sitemap - if idx+1 < len(config.sitemap) { - next = config.sitemap[idx+1] - } - - err = config.genPage(tmpl, &Page{ - Page: toc.Page, - Data: d, - Prev: prev, - Next: next, - Sitemap: config.sitemap, - }) - if err != nil { - return err - } - - } - - return nil -} - -type Sitemap struct { - ParentHref string - Text string - Href string - Page string - Children []*Sitemap -} - -func (sitemap *Sitemap) Slug() string { - return strings.ReplaceAll( - strings.ToLower(sitemap.Text), - " ", - "-", - ) -} - -func (sitemap *Sitemap) GenHref() template.HTML { - if sitemap.Href == "" { - return template.HTML(fmt.Sprintf("%s#%s", sitemap.ParentHref, sitemap.Slug())) - } - return template.HTML(sitemap.Href) -} - func main() { - pager := page("./docs/docs") - sitemap := []*Sitemap{ + pager := pdocs.Pager("./docs/docs") + sitemap := []*pdocs.Sitemap{ {Text: "Marketing", Href: "/", Page: pager("marketing.md")}, { Text: "How it Works", Href: "/how-it-works", Page: pager("how-it-works.md"), - Children: []*Sitemap{ + Children: []*pdocs.Sitemap{ {Text: "Port Forward"}, {Text: "Traditional VPN"}, {Text: "sish Public"}, @@ -292,7 +24,7 @@ func main() { Text: "Getting Started", Href: "/getting-started", Page: pager("getting-started.md"), - Children: []*Sitemap{ + Children: []*pdocs.Sitemap{ {Text: "Managed"}, {Text: "Docker"}, {Text: "Docker Compose"}, @@ -305,7 +37,7 @@ func main() { Text: "Forwarding Types", Href: "/forwarding-types", Page: pager("forwarding-types.md"), - Children: []*Sitemap{ + Children: []*pdocs.Sitemap{ {Text: "HTTP"}, {Text: "TCP"}, {Text: "TCP Alias"}, @@ -317,7 +49,7 @@ func main() { Text: "Advanced", Href: "/advanced", Page: pager("advanced.md"), - Children: []*Sitemap{ + Children: []*pdocs.Sitemap{ {Text: "Allowlist IPs"}, {Text: "Custom Domains"}, {Text: "Load Balancing"}, @@ -326,13 +58,14 @@ func main() { {Text: "FAQ", Href: "/faq", Page: pager("faq.md")}, } - config := &DocConfig{ - out: "./docs/public", - tmpl: "./docs/tmpl", - sitemap: sitemap, + config := &pdocs.DocConfig{ + Sitemap: sitemap, + Out: "./docs/public", + Tmpl: "./docs/tmpl", + PageTmpl: "post.page.tmpl", } - err := config.genSite() + err := config.GenSite() if err != nil { panic(err) } diff --git a/go.mod b/go.mod index f619be3..d265fcd 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,9 @@ module github.com/antoniomika/sish -go 1.21 +go 1.21.5 require ( github.com/ScaleFT/sshkeys v1.2.0 - github.com/alecthomas/chroma v0.10.0 github.com/antoniomika/syncmap v1.0.0 github.com/caddyserver/certmagic v0.19.2 github.com/fsnotify/fsnotify v1.6.0 @@ -13,27 +12,25 @@ require ( github.com/jpillora/ipfilter v1.2.9 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a + github.com/picosh/pdocs v0.0.0-20240108145604-582bbd2bcc23 github.com/pires/go-proxyproto v0.7.0 github.com/radovskyb/watcher v1.0.7 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.17.0 github.com/vulcand/oxy v1.4.2 - github.com/yuin/goldmark v1.5.3 - github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 - github.com/yuin/goldmark-meta v1.1.0 - go.abhg.dev/goldmark/anchor v0.1.1 golang.org/x/crypto v0.14.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect + github.com/alecthomas/chroma v0.10.0 // indirect github.com/bytedance/sonic v1.10.2 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect - github.com/dlclark/regexp2 v1.4.0 // indirect + github.com/dlclark/regexp2 v1.10.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -67,7 +64,11 @@ require ( github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect + github.com/yuin/goldmark v1.6.0 // indirect + github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 // indirect + github.com/yuin/goldmark-meta v1.1.0 // indirect github.com/zeebo/blake3 v0.2.3 // indirect + go.abhg.dev/goldmark/anchor v0.1.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/arch v0.5.0 // indirect diff --git a/go.sum b/go.sum index 2b9a856..1871532 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,8 @@ github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFn github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= +github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -240,6 +242,10 @@ github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdU github.com/phuslu/iploc v1.0.20230201/go.mod h1:gsgExGWldwv1AEzZm+Ki9/vGfyjkL33pbSr9HGpt2Xg= github.com/phuslu/iploc v1.0.20230929 h1:UkCm2if3LKQB96TWU4axkm4AWDmAV1vC6y71bimf57w= github.com/phuslu/iploc v1.0.20230929/go.mod h1:gsgExGWldwv1AEzZm+Ki9/vGfyjkL33pbSr9HGpt2Xg= +github.com/picosh/pdocs v0.0.0-20240108145136-a967fbcd7e48 h1:bnMEkxsSmLvXm5uo+JVuHDWu2U3xx8rpMZL0GS7vaX8= +github.com/picosh/pdocs v0.0.0-20240108145136-a967fbcd7e48/go.mod h1:rh8n5EosoD8svAbVPUEuXWfcWBsGj3GPeG/8D/0Az3c= +github.com/picosh/pdocs v0.0.0-20240108145604-582bbd2bcc23 h1:gnUGSuxipJYPRyJlvgKOxWEgKDPkCWvF5b9duXJTxBM= +github.com/picosh/pdocs v0.0.0-20240108145604-582bbd2bcc23/go.mod h1:rh8n5EosoD8svAbVPUEuXWfcWBsGj3GPeG/8D/0Az3c= github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -304,8 +310,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= -github.com/yuin/goldmark v1.5.3 h1:3HUJmBFbQW9fhQOzMgseU134xfi6hU+mjWywx5Ty+/M= -github.com/yuin/goldmark v1.5.3/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= +github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg= github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU= github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=