json.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // Package json minifies JSON following the specifications at http://json.org/.
  2. package json
  3. import (
  4. "io"
  5. "github.com/tdewolff/minify/v2"
  6. "github.com/tdewolff/parse/v2"
  7. "github.com/tdewolff/parse/v2/json"
  8. )
  9. var (
  10. commaBytes = []byte(",")
  11. colonBytes = []byte(":")
  12. zeroBytes = []byte("0")
  13. minusZeroBytes = []byte("-0")
  14. )
  15. ////////////////////////////////////////////////////////////////
  16. // Minifier is a JSON minifier.
  17. type Minifier struct {
  18. Precision int // number of significant digits
  19. KeepNumbers bool // prevent numbers from being minified
  20. }
  21. // Minify minifies JSON data, it reads from r and writes to w.
  22. func Minify(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error {
  23. return (&Minifier{}).Minify(m, w, r, params)
  24. }
  25. // Minify minifies JSON data, it reads from r and writes to w.
  26. func (o *Minifier) Minify(_ *minify.M, w io.Writer, r io.Reader, _ map[string]string) error {
  27. skipComma := true
  28. z := parse.NewInput(r)
  29. defer z.Restore()
  30. p := json.NewParser(z)
  31. for {
  32. state := p.State()
  33. gt, text := p.Next()
  34. if gt == json.ErrorGrammar {
  35. if _, err := w.Write(nil); err != nil {
  36. return err
  37. }
  38. if p.Err() != io.EOF {
  39. return p.Err()
  40. }
  41. return nil
  42. }
  43. if !skipComma && gt != json.EndObjectGrammar && gt != json.EndArrayGrammar {
  44. if state == json.ObjectKeyState || state == json.ArrayState {
  45. w.Write(commaBytes)
  46. } else if state == json.ObjectValueState {
  47. w.Write(colonBytes)
  48. }
  49. }
  50. skipComma = gt == json.StartObjectGrammar || gt == json.StartArrayGrammar
  51. if !o.KeepNumbers && 0 < len(text) && ('0' <= text[0] && text[0] <= '9' || text[0] == '-') {
  52. text = minify.Number(text, o.Precision)
  53. if text[0] == '.' {
  54. w.Write(zeroBytes)
  55. } else if 1 < len(text) && text[0] == '-' && text[1] == '.' {
  56. text = text[1:]
  57. w.Write(minusZeroBytes)
  58. }
  59. }
  60. w.Write(text)
  61. }
  62. }