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  }