/pkg/stdlib/strings/fmt.go

https://github.com/MontFerret/ferret · Go · 87 lines · 63 code · 18 blank · 6 comment · 17 complexity · c16ddf539dff25bf742a7428aeae4849 MD5 · raw file

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