mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 07:12:26 -05:00 
			
		
		
		
	* start fixing up tests * fix up tests + automate with drone * fiddle with linting * messing about with drone.yml * some more fiddling * hmmm * add cache * add vendor directory * verbose * ci updates * update some little things * update sig
		
			
				
	
	
		
			230 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			230 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package css
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	indentSpace = 2
 | |
| )
 | |
| 
 | |
| // RuleKind represents a Rule kind
 | |
| type RuleKind int
 | |
| 
 | |
| // Rule kinds
 | |
| const (
 | |
| 	QualifiedRule RuleKind = iota
 | |
| 	AtRule
 | |
| )
 | |
| 
 | |
| // At Rules than have Rules inside their block instead of Declarations
 | |
| var atRulesWithRulesBlock = []string{
 | |
| 	"@document", "@font-feature-values", "@keyframes", "@media", "@supports",
 | |
| }
 | |
| 
 | |
| // Rule represents a parsed CSS rule
 | |
| type Rule struct {
 | |
| 	Kind RuleKind
 | |
| 
 | |
| 	// At Rule name (eg: "@media")
 | |
| 	Name string
 | |
| 
 | |
| 	// Raw prelude
 | |
| 	Prelude string
 | |
| 
 | |
| 	// Qualified Rule selectors parsed from prelude
 | |
| 	Selectors []string
 | |
| 
 | |
| 	// Style properties
 | |
| 	Declarations []*Declaration
 | |
| 
 | |
| 	// At Rule embedded rules
 | |
| 	Rules []*Rule
 | |
| 
 | |
| 	// Current rule embedding level
 | |
| 	EmbedLevel int
 | |
| }
 | |
| 
 | |
| // NewRule instanciates a new Rule
 | |
| func NewRule(kind RuleKind) *Rule {
 | |
| 	return &Rule{
 | |
| 		Kind: kind,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Returns string representation of rule kind
 | |
| func (kind RuleKind) String() string {
 | |
| 	switch kind {
 | |
| 	case QualifiedRule:
 | |
| 		return "Qualified Rule"
 | |
| 	case AtRule:
 | |
| 		return "At Rule"
 | |
| 	default:
 | |
| 		return "WAT"
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // EmbedsRules returns true if this rule embeds another rules
 | |
| func (rule *Rule) EmbedsRules() bool {
 | |
| 	if rule.Kind == AtRule {
 | |
| 		for _, atRuleName := range atRulesWithRulesBlock {
 | |
| 			if rule.Name == atRuleName {
 | |
| 				return true
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // Equal returns true if both rules are equals
 | |
| func (rule *Rule) Equal(other *Rule) bool {
 | |
| 	if (rule.Kind != other.Kind) ||
 | |
| 		(rule.Prelude != other.Prelude) ||
 | |
| 		(rule.Name != other.Name) {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	if (len(rule.Selectors) != len(other.Selectors)) ||
 | |
| 		(len(rule.Declarations) != len(other.Declarations)) ||
 | |
| 		(len(rule.Rules) != len(other.Rules)) {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	for i, sel := range rule.Selectors {
 | |
| 		if sel != other.Selectors[i] {
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for i, decl := range rule.Declarations {
 | |
| 		if !decl.Equal(other.Declarations[i]) {
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for i, rule := range rule.Rules {
 | |
| 		if !rule.Equal(other.Rules[i]) {
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // Diff returns a string representation of rules differences
 | |
| func (rule *Rule) Diff(other *Rule) []string {
 | |
| 	result := []string{}
 | |
| 
 | |
| 	if rule.Kind != other.Kind {
 | |
| 		result = append(result, fmt.Sprintf("Kind: %s | %s", rule.Kind.String(), other.Kind.String()))
 | |
| 	}
 | |
| 
 | |
| 	if rule.Prelude != other.Prelude {
 | |
| 		result = append(result, fmt.Sprintf("Prelude: \"%s\" | \"%s\"", rule.Prelude, other.Prelude))
 | |
| 	}
 | |
| 
 | |
| 	if rule.Name != other.Name {
 | |
| 		result = append(result, fmt.Sprintf("Name: \"%s\" | \"%s\"", rule.Name, other.Name))
 | |
| 	}
 | |
| 
 | |
| 	if len(rule.Selectors) != len(other.Selectors) {
 | |
| 		result = append(result, fmt.Sprintf("Selectors: %v | %v", strings.Join(rule.Selectors, ", "), strings.Join(other.Selectors, ", ")))
 | |
| 	} else {
 | |
| 		for i, sel := range rule.Selectors {
 | |
| 			if sel != other.Selectors[i] {
 | |
| 				result = append(result, fmt.Sprintf("Selector: \"%s\" | \"%s\"", sel, other.Selectors[i]))
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if len(rule.Declarations) != len(other.Declarations) {
 | |
| 		result = append(result, fmt.Sprintf("Declarations Nb: %d | %d", len(rule.Declarations), len(other.Declarations)))
 | |
| 	} else {
 | |
| 		for i, decl := range rule.Declarations {
 | |
| 			if !decl.Equal(other.Declarations[i]) {
 | |
| 				result = append(result, fmt.Sprintf("Declaration: \"%s\" | \"%s\"", decl.String(), other.Declarations[i].String()))
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if len(rule.Rules) != len(other.Rules) {
 | |
| 		result = append(result, fmt.Sprintf("Rules Nb: %d | %d", len(rule.Rules), len(other.Rules)))
 | |
| 	} else {
 | |
| 
 | |
| 		for i, rule := range rule.Rules {
 | |
| 			if !rule.Equal(other.Rules[i]) {
 | |
| 				result = append(result, fmt.Sprintf("Rule: \"%s\" | \"%s\"", rule.String(), other.Rules[i].String()))
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // Returns the string representation of a rule
 | |
| func (rule *Rule) String() string {
 | |
| 	result := ""
 | |
| 
 | |
| 	if rule.Kind == QualifiedRule {
 | |
| 		for i, sel := range rule.Selectors {
 | |
| 			if i != 0 {
 | |
| 				result += ", "
 | |
| 			}
 | |
| 			result += sel
 | |
| 		}
 | |
| 	} else {
 | |
| 		// AtRule
 | |
| 		result += fmt.Sprintf("%s", rule.Name)
 | |
| 
 | |
| 		if rule.Prelude != "" {
 | |
| 			if result != "" {
 | |
| 				result += " "
 | |
| 			}
 | |
| 			result += fmt.Sprintf("%s", rule.Prelude)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (len(rule.Declarations) == 0) && (len(rule.Rules) == 0) {
 | |
| 		result += ";"
 | |
| 	} else {
 | |
| 		result += " {\n"
 | |
| 
 | |
| 		if rule.EmbedsRules() {
 | |
| 			for _, subRule := range rule.Rules {
 | |
| 				result += fmt.Sprintf("%s%s\n", rule.indent(), subRule.String())
 | |
| 			}
 | |
| 		} else {
 | |
| 			for _, decl := range rule.Declarations {
 | |
| 				result += fmt.Sprintf("%s%s\n", rule.indent(), decl.String())
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		result += fmt.Sprintf("%s}", rule.indentEndBlock())
 | |
| 	}
 | |
| 
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // Returns identation spaces for declarations and rules
 | |
| func (rule *Rule) indent() string {
 | |
| 	result := ""
 | |
| 
 | |
| 	for i := 0; i < ((rule.EmbedLevel + 1) * indentSpace); i++ {
 | |
| 		result += " "
 | |
| 	}
 | |
| 
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // Returns identation spaces for end of block character
 | |
| func (rule *Rule) indentEndBlock() string {
 | |
| 	result := ""
 | |
| 
 | |
| 	for i := 0; i < (rule.EmbedLevel * indentSpace); i++ {
 | |
| 		result += " "
 | |
| 	}
 | |
| 
 | |
| 	return result
 | |
| }
 |