github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/common/paths/url.go (about) 1 // Copyright 2021 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package paths 15 16 import ( 17 "fmt" 18 "net/url" 19 "path" 20 "path/filepath" 21 "strings" 22 ) 23 24 type pathBridge struct{} 25 26 func (pathBridge) Base(in string) string { 27 return path.Base(in) 28 } 29 30 func (pathBridge) Clean(in string) string { 31 return path.Clean(in) 32 } 33 34 func (pathBridge) Dir(in string) string { 35 return path.Dir(in) 36 } 37 38 func (pathBridge) Ext(in string) string { 39 return path.Ext(in) 40 } 41 42 func (pathBridge) Join(elem ...string) string { 43 return path.Join(elem...) 44 } 45 46 func (pathBridge) Separator() string { 47 return "/" 48 } 49 50 var pb pathBridge 51 52 // MakePermalink combines base URL with content path to create full URL paths. 53 // Example 54 // 55 // base: http://spf13.com/ 56 // path: post/how-i-blog 57 // result: http://spf13.com/post/how-i-blog 58 func MakePermalink(host, plink string) *url.URL { 59 base, err := url.Parse(host) 60 if err != nil { 61 panic(err) 62 } 63 64 p, err := url.Parse(plink) 65 if err != nil { 66 panic(err) 67 } 68 69 if p.Host != "" { 70 panic(fmt.Errorf("can't make permalink from absolute link %q", plink)) 71 } 72 73 base.Path = path.Join(base.Path, p.Path) 74 75 // path.Join will strip off the last /, so put it back if it was there. 76 hadTrailingSlash := (plink == "" && strings.HasSuffix(host, "/")) || strings.HasSuffix(p.Path, "/") 77 if hadTrailingSlash && !strings.HasSuffix(base.Path, "/") { 78 base.Path = base.Path + "/" 79 } 80 81 return base 82 } 83 84 // AddContextRoot adds the context root to an URL if it's not already set. 85 // For relative URL entries on sites with a base url with a context root set (i.e. http://example.com/mysite), 86 // relative URLs must not include the context root if canonifyURLs is enabled. But if it's disabled, it must be set. 87 func AddContextRoot(baseURL, relativePath string) string { 88 url, err := url.Parse(baseURL) 89 if err != nil { 90 panic(err) 91 } 92 93 newPath := path.Join(url.Path, relativePath) 94 95 // path strips trailing slash, ignore root path. 96 if newPath != "/" && strings.HasSuffix(relativePath, "/") { 97 newPath += "/" 98 } 99 return newPath 100 } 101 102 // URLizeAn 103 104 // PrettifyURL takes a URL string and returns a semantic, clean URL. 105 func PrettifyURL(in string) string { 106 x := PrettifyURLPath(in) 107 108 if path.Base(x) == "index.html" { 109 return path.Dir(x) 110 } 111 112 if in == "" { 113 return "/" 114 } 115 116 return x 117 } 118 119 // PrettifyURLPath takes a URL path to a content and converts it 120 // to enable pretty URLs. 121 // 122 // /section/name.html becomes /section/name/index.html 123 // /section/name/ becomes /section/name/index.html 124 // /section/name/index.html becomes /section/name/index.html 125 func PrettifyURLPath(in string) string { 126 return prettifyPath(in, pb) 127 } 128 129 // Uglify does the opposite of PrettifyURLPath(). 130 // 131 // /section/name/index.html becomes /section/name.html 132 // /section/name/ becomes /section/name.html 133 // /section/name.html becomes /section/name.html 134 func Uglify(in string) string { 135 if path.Ext(in) == "" { 136 if len(in) < 2 { 137 return "/" 138 } 139 // /section/name/ -> /section/name.html 140 return path.Clean(in) + ".html" 141 } 142 143 name, ext := fileAndExt(in, pb) 144 if name == "index" { 145 // /section/name/index.html -> /section/name.html 146 d := path.Dir(in) 147 if len(d) > 1 { 148 return d + ext 149 } 150 return in 151 } 152 // /.xml -> /index.xml 153 if name == "" { 154 return path.Dir(in) + "index" + ext 155 } 156 // /section/name.html -> /section/name.html 157 return path.Clean(in) 158 } 159 160 // UrlToFilename converts the URL s to a filename. 161 // If ParseRequestURI fails, the input is just converted to OS specific slashes and returned. 162 func UrlToFilename(s string) (string, bool) { 163 u, err := url.ParseRequestURI(s) 164 165 if err != nil { 166 return filepath.FromSlash(s), false 167 } 168 169 p := u.Path 170 171 if p == "" { 172 p, _ = url.QueryUnescape(u.Opaque) 173 return filepath.FromSlash(p), true 174 } 175 176 p = filepath.FromSlash(p) 177 178 if u.Host != "" { 179 // C:\data\file.txt 180 p = strings.ToUpper(u.Host) + ":" + p 181 } 182 183 return p, true 184 }