github.com/MontFerret/ferret@v0.18.0/pkg/stdlib/strings/fmt.go (about)

     1  package strings
     2  
     3  import (
     4  	"context"
     5  	"regexp"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/MontFerret/ferret/pkg/runtime/core"
    12  	"github.com/MontFerret/ferret/pkg/runtime/values"
    13  	"github.com/MontFerret/ferret/pkg/runtime/values/types"
    14  )
    15  
    16  // FMT formats the template using these arguments.
    17  // @param {String} template - template.
    18  // @param {Any, repeated} args - template arguments.
    19  // @return {String} - string formed by template using arguments.
    20  func Fmt(_ context.Context, args ...core.Value) (core.Value, error) {
    21  	err := core.ValidateArgs(args, 1, core.MaxArgs)
    22  	if err != nil {
    23  		return values.None, err
    24  	}
    25  
    26  	err = core.ValidateType(args[0], types.String)
    27  	if err != nil {
    28  		return values.None, err
    29  	}
    30  
    31  	formatted, err := format(args[0].String(), args[1:])
    32  	if err != nil {
    33  		return values.None, err
    34  	}
    35  
    36  	return values.NewString(formatted), nil
    37  }
    38  
    39  func format(template string, args []core.Value) (string, error) {
    40  	rgx := regexp.MustCompile("{[0-9]*}")
    41  
    42  	argsCount := len(args)
    43  	emptyBracketsCount := strings.Count(template, "{}")
    44  
    45  	if argsCount > emptyBracketsCount && emptyBracketsCount != 0 {
    46  		return "", errors.Errorf("there are arguments that have never been used")
    47  	}
    48  
    49  	var betweenBrackets string
    50  	var n int
    51  	// index of the last value
    52  	// inserted into the template
    53  	var lastArgIdx int
    54  	var err error
    55  
    56  	template = rgx.ReplaceAllStringFunc(template, func(s string) string {
    57  		if err != nil {
    58  			return ""
    59  		}
    60  
    61  		betweenBrackets = s[1 : len(s)-1]
    62  
    63  		if betweenBrackets == "" {
    64  			if argsCount <= lastArgIdx {
    65  				err = errors.Errorf("not enough arguments")
    66  				return ""
    67  			}
    68  
    69  			lastArgIdx++
    70  			return args[lastArgIdx-1].String()
    71  		}
    72  
    73  		n, err = strconv.Atoi(betweenBrackets)
    74  		if err != nil {
    75  			err = errors.Errorf("failed to parse int: %v", err)
    76  			return ""
    77  		}
    78  
    79  		if n >= argsCount {
    80  			err = errors.Errorf("invalid reference to argument `%d`", n)
    81  			return ""
    82  		}
    83  
    84  		return args[n].String()
    85  	})
    86  
    87  	return template, err
    88  }