Fix some missing JS class collector cases
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 27 Apr 2020 15:49:51 +0000 (17:49 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 27 Apr 2020 17:06:29 +0000 (19:06 +0200)
Fixes #7216

publisher/htmlElementsCollector.go
publisher/htmlElementsCollector_test.go

index 6166c49adbb536857b9289cc57350e9c10d5d754..e033f52d71698974f1e5248510f07df52a985105 100644 (file)
 package publisher
 
 import (
+       "regexp"
+
        "github.com/gohugoio/hugo/helpers"
        "golang.org/x/net/html"
-       yaml "gopkg.in/yaml.v2"
 
        "bytes"
        "sort"
@@ -196,7 +197,10 @@ func isQuote(b byte) bool {
        return b == '"' || b == '\''
 }
 
-var htmlJsonFixer = strings.NewReplacer(", ", "\n")
+var (
+       htmlJsonFixer = strings.NewReplacer(", ", "\n")
+       jsonAttrRe    = regexp.MustCompile(`'?(.*?)'?:.*`)
+)
 
 func parseHTMLElement(elStr string) (el htmlElement) {
        elStr = strings.TrimSpace(elStr)
@@ -225,27 +229,15 @@ func parseHTMLElement(elStr string) (el htmlElement) {
                                                val := strings.TrimSpace(a.Val)
                                                if strings.Contains(key, "class") && strings.HasPrefix(val, "{") {
                                                        // This looks like a Vue or AlpineJS class binding.
-                                                       // Try to unmarshal it as YAML and pull the keys.
-                                                       // This may look odd, as the source is (probably) JS (JSON), but the YAML
-                                                       // parser is much more lenient with simple JS input, it seems.
-                                                       m := make(map[string]interface{})
                                                        val = htmlJsonFixer.Replace(strings.Trim(val, "{}"))
-                                                       // Remove leading space to make it look like YAML.
                                                        lines := strings.Split(val, "\n")
                                                        for i, l := range lines {
                                                                lines[i] = strings.TrimSpace(l)
                                                        }
                                                        val = strings.Join(lines, "\n")
-                                                       err := yaml.Unmarshal([]byte(val), &m)
-                                                       if err == nil {
-                                                               for k := range m {
-                                                                       el.Classes = append(el.Classes, strings.Fields(k)...)
-                                                               }
-                                                       } else {
-                                                               // Just insert the raw values. This is used for CSS class pruning
-                                                               // so, it's important not to leave out values that may be a CSS class.
-                                                               el.Classes = append(el.Classes, strings.Fields(val)...)
-                                                       }
+                                                       val = jsonAttrRe.ReplaceAllString(val, "$1")
+                                                       el.Classes = append(el.Classes, strings.Fields(val)...)
+
                                                }
                                        }
                                }
index fe3876ae62507e2e4aa1162d798e86fe74da04c2..72abd94f07d1d35c14a6486fffaff15cdcf39cbe 100644 (file)
@@ -70,6 +70,15 @@ func TestClassCollector(t *testing.T) {
                {"Alpine bind 4", `<div x-bind:class="{ 'text-gray-800':  !checked, 
                                         'text-white': checked }"></div>`, f("div", "text-gray-800 text-white", "")},
 
+               {"Alpine bind 5", `<a x-bind:class="{
+                'text-a': a && b,
+                'text-b': !a && b || c,
+                'pl-3': a === 1,
+                 pl-2: b == 3,
+                'text-gray-600': (a > 1)
+      
+                }" class="block w-36 cursor-pointer pr-3 no-underline capitalize"></a>`, f("a", "block capitalize cursor-pointer no-underline pl-2 pl-3 pr-3 text-a text-b text-gray-600 w-36", "")},
+
                {"Vue bind", `<div v-bind:class="{ active: isActive }"></div>`, f("div", "active", "")},
        } {
                c.Run(test.name, func(c *qt.C) {