ref: b909983f2fb87c116fc225b34eb19909275862a6
dir: /style/css.go/
package style import ( "fmt" "github.com/psilva261/opossum/logger" "github.com/tdewolff/parse/v2" "github.com/tdewolff/parse/v2/css" "io" "strings" ) type Sheet struct { Rules []Rule } type Rule struct { Prelude string Selectors []Selector Declarations []Declaration Rules []Rule } type Selector struct { Val string } type Declaration struct { Important bool Prop string Val string } func Parse(rd io.Reader, inline bool) (s Sheet, err error) { s.Rules = make([]Rule, 0, 1000) stack := make([]Rule, 0, 2) selectors := make([]Selector, 0, 1) p := css.NewParser(parse.NewInput(rd), inline) if inline { stack = append(stack, Rule{}) defer func() { s.Rules = append(s.Rules, stack[0]) }() } for { gt, _, data := p.Next() switch gt { case css.ErrorGrammar: if err := p.Err(); err == io.EOF { return s, nil } else { return s, fmt.Errorf("next: %v", err) } break case css.QualifiedRuleGrammar: sel := Selector{} for _, val := range p.Values() { sel.Val += string(val.Data) } selectors = append(selectors, sel) case css.AtRuleGrammar, css.BeginAtRuleGrammar, css.BeginRulesetGrammar, css.DeclarationGrammar, css.CustomPropertyGrammar: var d Declaration if gt == css.BeginRulesetGrammar || gt == css.BeginAtRuleGrammar || gt == css.AtRuleGrammar { // TODO: why also gt == css.AtRuleGrammar? some sites crash otherwise stack = append(stack, Rule{}) } r := &(stack[len(stack)-1]) if gt == css.DeclarationGrammar || gt == css.CustomPropertyGrammar { d.Prop = string(data) } if gt == css.BeginAtRuleGrammar { r.Prelude = string(data) } vals := p.Values() for i, val := range vals { if gt == css.DeclarationGrammar || gt == css.CustomPropertyGrammar { if string(val.Data) == "!" && len(vals) == i+2 && string(vals[i+1].Data) == "important" { d.Important = true break } else { d.Val += string(val.Data) } } else if gt == css.BeginRulesetGrammar { if len(selectors) == 0 { sel := Selector{ Val: string(val.Data), } selectors = append(selectors, sel) } else { selectors[len(selectors)-1].Val += string(val.Data) } } else if gt == css.BeginAtRuleGrammar { r.Prelude += string(val.Data) } else { } } if gt == css.DeclarationGrammar || gt == css.CustomPropertyGrammar { d.Val = strings.TrimSpace(d.Val) r.Declarations = append(r.Declarations, d) } case css.EndRulesetGrammar, css.EndAtRuleGrammar: var r Rule if len(stack) == 1 { r, stack = stack[len(stack)-1], stack[:len(stack)-1] r.Selectors = append([]Selector{}, selectors...) s.Rules = append(s.Rules, r) } else { p := &(stack[len(stack)-2]) r, stack = stack[len(stack)-1], stack[:len(stack)-1] r.Selectors = append([]Selector{}, selectors...) p.Rules = append(p.Rules, r) } selectors = make([]Selector, 0, 1) case css.CommentGrammar: default: log.Errorf("unknown token type %+v", gt) } } return }