diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2023-07-19 17:32:19 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2023-07-19 19:50:37 +0200 |
commit | d8c94c354afb286b4fba9b883e49c1bd2c326bb3 (patch) | |
tree | f5bbfecaa72eee43fd5b004452dafd7753f72ad5 /publisher/htmlElementsCollector.go | |
parent | 6bbec9001445f623cead19de6811ee960cc53a10 (diff) |
publisher: Improve class collector for dynamic classes
E.g.
* AlpinesJS' :class="isTrue 'class1' : 'class2'"
* And dynamic classes with colon in them, e.g. `hover:bg-white`
Diffstat (limited to 'publisher/htmlElementsCollector.go')
-rw-r--r-- | publisher/htmlElementsCollector.go | 56 |
1 files changed, 46 insertions, 10 deletions
diff --git a/publisher/htmlElementsCollector.go b/publisher/htmlElementsCollector.go index c9d81818c..6c01fd8d9 100644 --- a/publisher/htmlElementsCollector.go +++ b/publisher/htmlElementsCollector.go @@ -32,7 +32,7 @@ const eof = -1 var ( htmlJsonFixer = strings.NewReplacer(", ", "\n") - jsonAttrRe = regexp.MustCompile(`'?(.*?)'?:.*`) + jsonAttrRe = regexp.MustCompile(`'?(.*?)'?:\s.*`) classAttrRe = regexp.MustCompile(`(?i)^class$|transition`) skipInnerElementRe = regexp.MustCompile(`(?i)^(pre|textarea|script|style)`) @@ -404,21 +404,31 @@ func (w *htmlElementsCollectorWriter) parseHTMLElement(elStr string) (el htmlEle if conf.DisableClasses { continue } + if classAttrRe.MatchString(a.Key) { el.Classes = append(el.Classes, strings.Fields(a.Val)...) } else { key := strings.ToLower(a.Key) val := strings.TrimSpace(a.Val) - if strings.Contains(key, "class") && strings.HasPrefix(val, "{") { - // This looks like a Vue or AlpineJS class binding. - val = htmlJsonFixer.Replace(strings.Trim(val, "{}")) - lines := strings.Split(val, "\n") - for i, l := range lines { - lines[i] = strings.TrimSpace(l) + + if strings.Contains(key, ":class") { + if strings.HasPrefix(val, "{") { + // This looks like a Vue or AlpineJS class binding. + val = htmlJsonFixer.Replace(strings.Trim(val, "{}")) + lines := strings.Split(val, "\n") + for i, l := range lines { + lines[i] = strings.TrimSpace(l) + } + val = strings.Join(lines, "\n") + + val = jsonAttrRe.ReplaceAllString(val, "$1") + + el.Classes = append(el.Classes, strings.Fields(val)...) } - val = strings.Join(lines, "\n") - val = jsonAttrRe.ReplaceAllString(val, "$1") - el.Classes = append(el.Classes, strings.Fields(val)...) + // Also add single quoted strings. + // This may introduce some false positives, but it covers some missing cases in the above. + // E.g. AlpinesJS' :class="isTrue 'class1' : 'class2'" + el.Classes = append(el.Classes, extractSingleQuotedStrings(val)...) } } } @@ -519,3 +529,29 @@ LOOP: func isSpace(b byte) bool { return b == ' ' || b == '\t' || b == '\n' } + +func extractSingleQuotedStrings(s string) []string { + var ( + inQuote bool + lo int + hi int + ) + + var words []string + + for i, r := range s { + switch { + case r == '\'': + if !inQuote { + inQuote = true + lo = i + 1 + } else { + inQuote = false + hi = i + words = append(words, strings.Fields(s[lo:hi])...) + } + } + } + + return words +} |