mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 19:42:25 -06: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
 | 
						|
}
 |