vanng822/go-premailer

Leftover CSS rules are wrongly escaped

Closed this issue · 5 comments

Leftover rules for selectors which cannot be applied to elements (e.g. :hover) are escaped in resulting style.

Take the simplest HTML input file in.html

<html>

<head>
    <style>
        .test {
            background-color: red;
            padding: 10px;
        }

        .test:hover {
            background-color: green;
        }
    </style>
</head>

<body>
    <div class="test">Test</div>
</body>

</html>
package main

import (
	"os"

	"github.com/vanng822/go-premailer/premailer"
)

func main() {
	p, err := premailer.NewPremailerFromFile("in.html", premailer.NewOptions())
	if err != nil {
		panic(err)
	}

	out, err := p.Transform()
	if err != nil {
		panic(err)
	}

	f, err := os.Create("out.html")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	f.WriteString(out)
}

After running the Transform(), leftover rules are escaped, which makes it invalid CSS, that is, rules won't be applied to elements.

out.html (formatted for clarity)

<html>

<head>
    <style type="text/css">
        ".test:hover" {
            background-color: green !important
        }
    </style>
</head>

<body>
    <div class="test" style="background-color:red;padding:10px">Test</div>
</body>

</html>

After some digging I found the culprit.

func copyRule(selector string, rule *css.CSSRule) *css.CSSRule {
// copy rule for each selector
styles := make([]*css.CSSStyleDeclaration, 0)
for _, s := range rule.Style.Styles {
styles = append(styles, css.NewCSSStyleDeclaration(s.Property, s.Value.Text(), s.Important))
}
copiedStyle := css.CSSStyleRule{Selector: css.NewCSSValueString(selector), Styles: styles}
copiedRule := &css.CSSRule{Type: rule.Type, Style: copiedStyle}
return copiedRule
}

Line 13 copiedStyle := css.CSSStyleRule{Selector: css.NewCSSValueString(selector), Styles: styles} uses css.NewCSSValueString from your other project https://github.com/vanng822/css which escapes the CSS rule.

func NewCSSValueString(data string) *CSSValue {
	data = strings.ReplaceAll(data, `\`, `\\`)
	data = strings.ReplaceAll(data, `"`, `\"`)
	data = `"` + data + `"`
	token := scanner.Token{scanner.TokenString, data, 0, 0}
	return &CSSValue{Tokens: []*scanner.Token{&token}}
}

Does this have to be changed in css project or is it possible to patch it here?

thanks @nikolagava

Please change in css-project. I wonder if it does just appear or it have been there all the time?

@vanng822 Looks like these changes were made about 2 years ago.
Premailer: 5392cc8
CSS: vanng822/css@6ba7c46

But, what if we used css.NewCSSValue instead of css.NewCSSValueString in copyRule function? I see that characters \ and " are escaped. Nevertheless, all premailer tests pass with this one change.

Thanks, quite long time not working with those :-D

ok, then probably better to fix it in this repo by using your suggestion. I think it would be ok not escaping since we are not allowed remote loading of css yet.