github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/utils/docgen/api/functions.go (about) 1 package docgen 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "os" 8 "regexp" 9 "sort" 10 "strconv" 11 "strings" 12 "text/template" 13 "time" 14 15 "github.com/lmorg/murex/utils/envvars" 16 ) 17 18 var funcMap = template.FuncMap{ 19 "md": funcMarkdown, 20 "quote": funcQuote, 21 "trim": strings.TrimSpace, 22 "doc": funcRenderedDocuments, 23 "cat": funcRenderedCategories, 24 "link": funcLink, 25 "linkbm": funcLinkBookmark, 26 "file": funcFile, 27 "notanindex": funcNotAnIndex, 28 "date": funcDate, 29 "time": funcTime, 30 "doct": funcDocT, 31 "othercats": funcOtherCats, 32 "otherdocs": funcOtherDocs, 33 "env": funcEnv, 34 } 35 36 /************ 37 * Markdown * 38 ************/ 39 40 // Takes: string (contents as read from YAML in a machine readable subset of markdown) 41 // Returns: markdown contents cleaned up for printing 42 func funcMarkdown(s string) string { 43 s = strings.ReplaceAll(s, "\r", "") 44 s = strings.TrimSuffix(s, "\n") 45 return s 46 } 47 48 /************ 49 * Quote * 50 ************/ 51 52 // Takes: strings (contents) 53 // Returns: contents with some characters escaped for printing in source code (eg \") 54 func funcQuote(s ...string) string { 55 return strconv.Quote(funcMarkdown(strings.Join(s, ""))) 56 } 57 58 /************ 59 * Doc * 60 ************/ 61 62 // Takes: string (category name), string (document name), int (index of rendered document template) 63 // Returns: contents of rendered document template 64 func funcRenderedDocuments(cat, doc string, index int) (string, error) { 65 if len(Config.renderedDocuments[cat]) == 0 { 66 return "", errors.New("category does not exist, doesn't have any documents, or hasn't yet been parsed") 67 } 68 69 if len(Config.renderedDocuments[cat][doc]) <= index { 70 return "", errors.New("index greater than number of templates currently parsed for that document") 71 } 72 73 return Config.renderedDocuments[cat][doc][index], nil 74 } 75 76 /************ 77 * Cat * 78 ************/ 79 80 // Takes: string (category name) and int (index of rendered category template) 81 // Returns: contents of rendered category template 82 func funcRenderedCategories(cat string, index int) (string, error) { 83 if len(Config.renderedCategories[cat]) == 0 { 84 return "", errors.New("category does not exist or hasn't yet been parsed") 85 } 86 87 if len(Config.renderedCategories[cat]) <= index { 88 return "", errors.New("index greater than number of templates currently parsed for that category") 89 } 90 91 return Config.renderedCategories[cat][index], nil 92 } 93 94 /************ 95 * Link * 96 ************/ 97 98 // Takes: string (doc, description, relativePath prefix...) 99 // Returns: URL to document 100 func funcLink(description, docId string, relativePath ...string) string { 101 return funcLinkBookmark(description, docId, "", relativePath...) 102 } 103 104 /************ 105 * LinkBM * 106 ************/ 107 108 // Takes: string (doc, description, bookmark (w/o hash), relativePath prefix...) 109 // Returns: URL to document 110 func funcLinkBookmark(description, docId, bookmark string, relativePath ...string) string { 111 doc := Documents.ByID("", "???", docId) 112 if doc == nil { 113 panic(fmt.Sprintf("nil document (%s)", docId)) 114 } 115 116 cat := Config.Categories.ByID(doc.CategoryID) 117 path := cat.Templates[0].DocumentFilePath(doc) 118 119 if bookmark != "" { 120 path += "#" + bookmark 121 } 122 123 //if len(relativePath) > 0 { 124 path = strings.Join(relativePath, "/") + "/" + path 125 //} 126 127 if os.Getenv("DOCGEN_TARGET") == "vuepress" { 128 path = strings.Replace(path, "/docs", "", 1) 129 } 130 131 return fmt.Sprintf("[%s](%s)", description, path) 132 } 133 134 /************ 135 * Include * 136 ************/ 137 138 // Takes: string (contents) 139 // Looks for: {{ include "filename" }} 140 // Returns: document with search string replaced with contents of filename 141 func funcInclude(s string) string { 142 rx := regexp.MustCompile(`\{\{ include "([-_/.a-zA-Z0-9]+)" \}\}`) 143 if !rx.MatchString(s) { 144 return s 145 } 146 147 match := rx.FindAllStringSubmatch(s, -1) 148 for i := range match { 149 path := match[i][1] 150 f := fileReader(path) 151 b := bytes.TrimSpace(readAll(f)) 152 153 w := bytes.NewBuffer([]byte{}) 154 155 t := template.Must(template.New(path).Funcs(funcMap).Parse(string(b))) 156 if err := t.Execute(w, nil); err != nil { 157 panic(err.Error()) 158 } 159 160 s = strings.Replace(s, match[i][0], w.String(), -1) 161 } 162 163 return s 164 } 165 166 /************ 167 * File * 168 ************/ 169 170 // Takes: slice of strings (file path) 171 // Returns: contents of file based on a concatenation of the slice 172 func funcFile(path ...string) string { 173 f := fileReader(strings.Join(path, "")) 174 b := readAll(f) 175 return string(b) 176 } 177 178 func init() { 179 funcMap["include"] = funcInclude 180 } 181 182 /************ 183 *NotAnIndex* 184 ************/ 185 186 // Takes: number (eg variable) 187 // Returns: number incremented by 1 188 func funcNotAnIndex(i int) int { 189 return i + 1 190 } 191 192 /************ 193 * Date * 194 ************/ 195 196 // Takes: DateTime (time.Time) 197 // Returns: Date as string 198 func funcDate(dt time.Time) string { 199 return dt.Format("02.01.2006") 200 } 201 202 /************ 203 * Time * 204 ************/ 205 206 // Takes: DateTime (time.Time) 207 // Returns: Time as string 208 func funcTime(dt time.Time) string { 209 return dt.Format("15:04") 210 } 211 212 /************ 213 * doct * 214 ************/ 215 216 // Takes: string (category, document ID) 217 // Returns: document type 218 func funcDocT(cat, doc string) *document { 219 return Documents.ByID("!!!", cat, doc) 220 } 221 222 /************ 223 * OtherCats* 224 ************/ 225 226 // Returns: list of documents in that category 227 func funcOtherCats() []category { 228 return Config.Categories 229 } 230 231 /************ 232 * OtherDocs* 233 ************/ 234 235 // Takes: string (category ID) 236 // Returns: list of documents in that category 237 func funcOtherDocs(id string) (d documents) { 238 for i := range Documents { 239 if Documents[i].CategoryID == id { 240 d = append(d, Documents[i]) 241 } 242 } 243 244 sort.Sort(d) 245 return 246 } 247 248 /************ 249 * Env * 250 ************/ 251 252 // Takes: string (env, formatted: `key=val`) 253 // Returns: true or false if the env matches systems env 254 func funcEnv(env string) any { 255 if !strings.Contains(env, "=") { 256 s := os.Getenv(env) 257 if s == "" { 258 s = "undef" 259 } 260 return s 261 } 262 263 key, value := envvars.Split(env) 264 v := make(map[string]interface{}) 265 envvars.All(v) 266 s, _ := v[key].(string) 267 return s == value 268 }