github.com/Jeffail/benthos/v3@v3.65.0/internal/docs/bloblang.go (about) 1 package docs 2 3 import ( 4 "bytes" 5 "strings" 6 "text/template" 7 8 "github.com/Jeffail/benthos/v3/internal/bloblang/parser" 9 "github.com/Jeffail/benthos/v3/internal/bloblang/query" 10 ) 11 12 // LintBloblangMapping is function for linting a config field expected to be a 13 // bloblang mapping. 14 func LintBloblangMapping(ctx LintContext, line, col int, v interface{}) []Lint { 15 str, ok := v.(string) 16 if !ok { 17 return nil 18 } 19 if str == "" { 20 return nil 21 } 22 _, err := ctx.BloblangEnv.NewMapping(str) 23 if err == nil { 24 return nil 25 } 26 if mErr, ok := err.(*parser.Error); ok { 27 bline, bcol := parser.LineAndColOf([]rune(str), mErr.Input) 28 lint := NewLintError(line+bline-1, mErr.ErrorAtPositionStructured("", []rune(str))) 29 lint.Column = col + bcol 30 return []Lint{lint} 31 } 32 return []Lint{NewLintError(line, err.Error())} 33 } 34 35 // LintBloblangField is function for linting a config field expected to be an 36 // interpolation string. 37 func LintBloblangField(ctx LintContext, line, col int, v interface{}) []Lint { 38 str, ok := v.(string) 39 if !ok { 40 return nil 41 } 42 if str == "" { 43 return nil 44 } 45 e, err := ctx.BloblangEnv.NewField(str) 46 if err == nil { 47 if ctx.RejectDeprecated && e.ContainsDeprecated { 48 return []Lint{NewLintError(line, `interpolation string contains deprecated syntax, use the new bloblang syntax instead, e.g. ${!meta("foo")} instead of ${!metadata:foo}`)} 49 } 50 return nil 51 } 52 if mErr, ok := err.(*parser.Error); ok { 53 bline, bcol := parser.LineAndColOf([]rune(str), mErr.Input) 54 lint := NewLintError(line+bline-1, mErr.ErrorAtPositionStructured("", []rune(str))) 55 lint.Column = col + bcol 56 return []Lint{lint} 57 } 58 return []Lint{NewLintError(line, err.Error())} 59 } 60 61 type functionCategory struct { 62 Name string 63 Specs []query.FunctionSpec 64 } 65 66 type functionsContext struct { 67 Categories []functionCategory 68 } 69 70 var bloblangParamsTemplate = `{{define "parameters" -}} 71 {{if gt (len .Definitions) 0}} 72 #### Parameters 73 74 {{range $i, $param := .Definitions -}} 75 ` + "**`{{$param.Name}}`**" + ` <{{if $param.IsOptional}}(optional) {{end}}{{$param.ValueType}}{{if $param.DefaultValue}}, default ` + "`{{$param.PrettyDefault}}`" + `{{end}}> {{$param.Description}} 76 {{end -}} 77 {{end -}} 78 {{end -}} 79 ` 80 81 var bloblangFunctionsTemplate = bloblangParamsTemplate + `{{define "function_example" -}} 82 {{if gt (len .Summary) 0 -}} 83 {{.Summary}} 84 85 {{end -}} 86 87 ` + "```coffee" + ` 88 {{.Mapping}} 89 {{range $i, $result := .Results}} 90 # In: {{index $result 0}} 91 # Out: {{index $result 1}} 92 {{end -}} 93 ` + "```" + ` 94 {{end -}} 95 96 {{define "function_spec" -}} 97 ### ` + "`{{.Name}}`" + ` 98 99 {{if eq .Status "beta" -}} 100 BETA: This function is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 101 102 {{end -}} 103 {{.Description}} 104 {{template "parameters" .Params -}} 105 {{if gt (len .Examples) 0}} 106 #### Examples 107 108 {{range $i, $example := .Examples}} 109 {{template "function_example" $example -}} 110 {{end -}} 111 {{end -}} 112 113 {{end -}} 114 115 --- 116 title: Bloblang Functions 117 sidebar_label: Functions 118 description: A list of Bloblang functions 119 --- 120 121 <!-- 122 THIS FILE IS AUTOGENERATED! 123 124 To make changes please edit the contents of: 125 internal/bloblang/query/functions.go 126 internal/docs/bloblang.go 127 --> 128 129 import Tabs from '@theme/Tabs'; 130 import TabItem from '@theme/TabItem'; 131 132 Functions can be placed anywhere and allow you to extract information from your environment, generate values, or access data from the underlying message being mapped: 133 134 ` + "```coffee" + ` 135 root.doc.id = uuid_v4() 136 root.doc.received_at = now() 137 root.doc.host = hostname() 138 ` + "```" + ` 139 140 Functions support both named and nameless style arguments: 141 142 ` + "```coffee" + ` 143 root.values_one = range(start: 0, stop: this.max, step: 2) 144 root.values_two = range(0, this.max, 2) 145 ` + "```" + ` 146 147 {{range $i, $cat := .Categories -}} 148 ## {{$cat.Name}} 149 150 {{range $i, $spec := $cat.Specs -}} 151 {{template "function_spec" $spec}} 152 {{end -}} 153 {{end -}} 154 155 [error_handling]: /docs/configuration/error_handling 156 [field_paths]: /docs/configuration/field_paths 157 [meta_proc]: /docs/components/processors/metadata 158 [methods.encode]: /docs/guides/bloblang/methods#encode 159 [methods.string]: /docs/guides/bloblang/methods#string 160 ` 161 162 func prefixExamples(s []query.ExampleSpec) { 163 for _, spec := range s { 164 for i := range spec.Results { 165 spec.Results[i][0] = strings.ReplaceAll( 166 strings.TrimSuffix(spec.Results[i][0], "\n"), 167 "\n", "\n# ", 168 ) 169 spec.Results[i][1] = strings.ReplaceAll( 170 strings.TrimSuffix(spec.Results[i][1], "\n"), 171 "\n", "\n# ", 172 ) 173 } 174 } 175 } 176 177 // BloblangFunctionsMarkdown returns a markdown document for all Bloblang 178 // functions. 179 func BloblangFunctionsMarkdown() ([]byte, error) { 180 ctx := functionsContext{} 181 182 specs := query.FunctionDocs() 183 for _, s := range specs { 184 prefixExamples(s.Examples) 185 } 186 187 for _, cat := range []query.FunctionCategory{ 188 query.FunctionCategoryGeneral, 189 query.FunctionCategoryMessage, 190 query.FunctionCategoryEnvironment, 191 query.FunctionCategoryDeprecated, 192 } { 193 functions := functionCategory{ 194 Name: string(cat), 195 } 196 for _, spec := range specs { 197 if spec.Category == cat { 198 functions.Specs = append(functions.Specs, spec) 199 } 200 } 201 if len(functions.Specs) > 0 { 202 ctx.Categories = append(ctx.Categories, functions) 203 } 204 } 205 206 var buf bytes.Buffer 207 err := template.Must(template.New("functions").Parse(bloblangFunctionsTemplate)).Execute(&buf, ctx) 208 209 return buf.Bytes(), err 210 } 211 212 //------------------------------------------------------------------------------ 213 214 type methodCategory struct { 215 Name string 216 Specs []query.MethodSpec 217 } 218 219 type methodsContext struct { 220 Categories []methodCategory 221 General []query.MethodSpec 222 } 223 224 var bloblangMethodsTemplate = bloblangParamsTemplate + `{{define "method_example" -}} 225 {{if gt (len .Summary) 0 -}} 226 {{.Summary}} 227 228 {{end -}} 229 230 ` + "```coffee" + ` 231 {{.Mapping}} 232 {{range $i, $result := .Results}} 233 # In: {{index $result 0}} 234 # Out: {{index $result 1}} 235 {{end -}} 236 ` + "```" + ` 237 {{end -}} 238 239 {{define "method_spec" -}} 240 ### ` + "`{{.Name}}`" + ` 241 242 {{if eq .Status "beta" -}} 243 BETA: This method is mostly stable but breaking changes could still be made outside of major version releases if a fundamental problem with it is found. 244 245 {{end -}} 246 {{.Description}} 247 {{template "parameters" .Params -}} 248 {{if gt (len .Examples) 0}} 249 #### Examples 250 251 {{range $i, $example := .Examples}} 252 {{template "method_example" $example -}} 253 {{end -}} 254 {{end -}} 255 256 {{end -}} 257 258 --- 259 title: Bloblang Methods 260 sidebar_label: Methods 261 description: A list of Bloblang methods 262 --- 263 264 <!-- 265 THIS FILE IS AUTOGENERATED! 266 267 To make changes please edit the contents of: 268 internal/bloblang/query/methods.go 269 internal/bloblang/query/methods_strings.go 270 internal/docs/bloblang.go 271 --> 272 273 import Tabs from '@theme/Tabs'; 274 import TabItem from '@theme/TabItem'; 275 276 Methods provide most of the power in Bloblang as they allow you to augment values and can be added to any expression (including other methods): 277 278 ` + "```coffee" + ` 279 root.doc.id = this.thing.id.string().catch(uuid_v4()) 280 root.doc.reduced_nums = this.thing.nums.map_each(num -> if num < 10 { 281 deleted() 282 } else { 283 num - 10 284 }) 285 root.has_good_taste = ["pikachu","mewtwo","magmar"].contains(this.user.fav_pokemon) 286 ` + "```" + ` 287 288 Methods support both named and nameless style arguments: 289 290 ` + "```coffee" + ` 291 root.foo_one = this.(bar | baz).trim().replace(old: "dog", new: "cat") 292 root.foo_two = this.(bar | baz).trim().replace("dog", "cat") 293 ` + "```" + ` 294 295 {{if gt (len .General) 0 -}} 296 ## General 297 298 {{range $i, $spec := .General -}} 299 {{template "method_spec" $spec}} 300 {{end -}} 301 {{end -}} 302 303 {{range $i, $cat := .Categories -}} 304 ## {{$cat.Name}} 305 306 {{range $i, $spec := $cat.Specs -}} 307 {{template "method_spec" $spec}} 308 {{end -}} 309 {{end -}} 310 311 [field_paths]: /docs/configuration/field_paths 312 [methods.encode]: #encode 313 [methods.string]: #string 314 ` 315 316 func methodForCat(s query.MethodSpec, cat query.MethodCategory) (query.MethodSpec, bool) { 317 for _, c := range s.Categories { 318 if c.Category == cat { 319 spec := s 320 if len(c.Description) > 0 { 321 spec.Description = strings.TrimSpace(c.Description) 322 } 323 if len(c.Examples) > 0 { 324 spec.Examples = c.Examples 325 } 326 return spec, true 327 } 328 } 329 return s, false 330 } 331 332 // BloblangMethodsMarkdown returns a markdown document for all Bloblang methods. 333 func BloblangMethodsMarkdown() ([]byte, error) { 334 ctx := methodsContext{} 335 336 specs := query.MethodDocs() 337 for _, s := range specs { 338 prefixExamples(s.Examples) 339 for _, cat := range s.Categories { 340 prefixExamples(cat.Examples) 341 } 342 } 343 344 for _, cat := range []query.MethodCategory{ 345 query.MethodCategoryStrings, 346 query.MethodCategoryRegexp, 347 query.MethodCategoryNumbers, 348 query.MethodCategoryTime, 349 query.MethodCategoryCoercion, 350 query.MethodCategoryObjectAndArray, 351 query.MethodCategoryParsing, 352 query.MethodCategoryEncoding, 353 query.MethodCategoryGeoIP, 354 query.MethodCategoryDeprecated, 355 } { 356 methods := methodCategory{ 357 Name: string(cat), 358 } 359 for _, spec := range specs { 360 var ok bool 361 if spec, ok = methodForCat(spec, cat); ok { 362 methods.Specs = append(methods.Specs, spec) 363 } 364 } 365 if len(methods.Specs) > 0 { 366 ctx.Categories = append(ctx.Categories, methods) 367 } 368 } 369 370 for _, spec := range specs { 371 if len(spec.Categories) == 0 && spec.Status != query.StatusHidden { 372 spec.Description = strings.TrimSpace(spec.Description) 373 ctx.General = append(ctx.General, spec) 374 } 375 } 376 377 var buf bytes.Buffer 378 err := template.Must(template.New("methods").Parse(bloblangMethodsTemplate)).Execute(&buf, ctx) 379 380 return buf.Bytes(), err 381 }