escape.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. package raymond
  2. import (
  3. "bytes"
  4. "strings"
  5. )
  6. //
  7. // That whole file is borrowed from https://github.com/golang/go/tree/master/src/html/escape.go
  8. //
  9. // With changes:
  10. // &#39 => '
  11. // &#34 => "
  12. //
  13. // To stay in sync with JS implementation, and make mustache tests pass.
  14. //
  15. type writer interface {
  16. WriteString(string) (int, error)
  17. }
  18. const escapedChars = `&'<>"`
  19. func escape(w writer, s string) error {
  20. i := strings.IndexAny(s, escapedChars)
  21. for i != -1 {
  22. if _, err := w.WriteString(s[:i]); err != nil {
  23. return err
  24. }
  25. var esc string
  26. switch s[i] {
  27. case '&':
  28. esc = "&amp;"
  29. case '\'':
  30. esc = "&apos;"
  31. case '<':
  32. esc = "&lt;"
  33. case '>':
  34. esc = "&gt;"
  35. case '"':
  36. esc = "&quot;"
  37. default:
  38. panic("unrecognized escape character")
  39. }
  40. s = s[i+1:]
  41. if _, err := w.WriteString(esc); err != nil {
  42. return err
  43. }
  44. i = strings.IndexAny(s, escapedChars)
  45. }
  46. _, err := w.WriteString(s)
  47. return err
  48. }
  49. // Escape escapes special HTML characters.
  50. //
  51. // It can be used by helpers that return a SafeString and that need to escape some content by themselves.
  52. func Escape(s string) string {
  53. if strings.IndexAny(s, escapedChars) == -1 {
  54. return s
  55. }
  56. var buf bytes.Buffer
  57. escape(&buf, s)
  58. return buf.String()
  59. }