specificity.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. package premailer
  2. import (
  3. "regexp"
  4. "strings"
  5. )
  6. // https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
  7. // https://developer.mozilla.org/en-US/docs/Web/CSS/Reference#Selectors
  8. type specificity struct {
  9. important int
  10. idCount int
  11. classCount int
  12. typeCount int
  13. attrCount int
  14. ruleSetIndex int
  15. ruleIndex int
  16. }
  17. func (s *specificity) importantOrders() []int {
  18. return []int{s.important, s.idCount,
  19. s.classCount, s.attrCount,
  20. s.typeCount, s.ruleSetIndex,
  21. s.ruleIndex}
  22. }
  23. var typeSelectorRegex = regexp.MustCompile("(^|\\s)\\w")
  24. func makeSpecificity(important, ruleSetIndex, ruleIndex int, selector string) *specificity {
  25. spec := specificity{}
  26. // determine values for priority
  27. if important > 0 {
  28. spec.important = 1
  29. } else {
  30. spec.important = 0
  31. }
  32. spec.idCount = strings.Count(selector, "#")
  33. spec.classCount = strings.Count(selector, ".")
  34. spec.attrCount = strings.Count(selector, "[")
  35. spec.typeCount = len(typeSelectorRegex.FindAllString(selector, -1))
  36. spec.ruleSetIndex = ruleSetIndex
  37. spec.ruleIndex = ruleIndex
  38. return &spec
  39. }
  40. type bySpecificity []*styleRule
  41. func (bs bySpecificity) Len() int {
  42. return len(bs)
  43. }
  44. func (bs bySpecificity) Swap(i, j int) {
  45. bs[i], bs[j] = bs[j], bs[i]
  46. }
  47. func (bs bySpecificity) Less(i, j int) bool {
  48. iorders := bs[i].specificity.importantOrders()
  49. jorders := bs[j].specificity.importantOrders()
  50. for n, v := range iorders {
  51. if v < jorders[n] {
  52. return true
  53. }
  54. if v > jorders[n] {
  55. return false
  56. }
  57. }
  58. return false
  59. }