-
Notifications
You must be signed in to change notification settings - Fork 0
/
link_rewriter.go
132 lines (116 loc) · 3.37 KB
/
link_rewriter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package main
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyright (C) 2024 Thiago Kenji Okada <[email protected]>
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
import (
"log"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
// linkRewriter is the main struct for your extension
type linkRewriter struct {
prefixUrl string
posts posts
}
// NewLinkRewriter returns a new instance of LinkRewriter
func NewLinkRewriter(prefixUrl string, posts posts) *linkRewriter {
return &linkRewriter{prefixUrl, posts}
}
// Extend will be called by Goldmark to add your extension
func (e *linkRewriter) Extend(m goldmark.Markdown) {
m.Parser().AddOptions(parser.WithASTTransformers(util.Prioritized(e, 0)))
}
// Transform is the method that modifies the AST
func (e *linkRewriter) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
if link, ok := n.(*ast.Link); ok {
e.rewriteLink(link)
}
if image, ok := n.(*ast.Image); ok {
e.rewriteImage(image)
}
return ast.WalkContinue, nil
})
}
func hasAnyExtension(s string, extensions ...string) bool {
ext := filepath.Ext(s)
if ext == "" {
return false
}
for _, e := range extensions {
if ext == e {
return true
}
}
return false
}
// rewriteLink modifies the link URL
func (e *linkRewriter) rewriteLink(l *ast.Link) {
link := string(l.Destination)
if strings.HasPrefix(link, ".") {
log.Printf("[WARN]: relative link reference found: %s\n", link)
}
if strings.HasPrefix(link, "/") {
var dest string
if hasAnyExtension(link, ".png", ".jpg", ".jpeg") {
// If the link is an image, we will point it to
// blogRawUrl
if _, err := os.Stat(filepath.Join(".", link)); err == nil {
dest = must1(url.JoinPath(blogRawUrl, link))
} else {
log.Printf("[WARN] did not find image: %s\n", link)
return
}
} else if e.posts != nil {
// If posts are not nil, it means we will grab the slug
// from posts
post, ok := e.posts.Get(link[1:])
if ok {
dest = must1(url.JoinPath(e.prefixUrl, post.slug))
} else {
log.Printf("[WARN] did not find reference to link: %s\n", link)
return
}
} else {
// Else we will just append the prefixUrl to the link
if _, err := os.Stat(filepath.Join(".", link)); err == nil {
dest = must1(url.JoinPath(e.prefixUrl, link))
} else {
log.Printf("[WARN] did not find link: %s\n", link)
return
}
}
l.Destination = []byte(dest)
}
}
// rewriteImage modifies the image URL
func (e *linkRewriter) rewriteImage(i *ast.Image) {
image := string(i.Destination)
if strings.HasPrefix(image, ".") {
log.Printf("[WARN]: relative image link reference found: %s\n", image)
}
if strings.HasPrefix(image, "/") {
dest := must1(url.JoinPath(blogRawUrl, image))
i.Destination = []byte(dest)
}
}