shithub: mycel

ref: b909983f2fb87c116fc225b34eb19909275862a6
dir: /style/css.go/

View raw version
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
}