diff options
Diffstat (limited to 'resources/resource_transformers/tocss')
6 files changed, 144 insertions, 57 deletions
diff --git a/resources/resource_transformers/tocss/dartsass/client.go b/resources/resource_transformers/tocss/dartsass/client.go index 49cafb52d..f45e6537a 100644 --- a/resources/resource_transformers/tocss/dartsass/client.go +++ b/resources/resource_transformers/tocss/dartsass/client.go @@ -135,7 +135,7 @@ type Options struct { // Vars will be available in 'hugo:vars', e.g: // @use "hugo:vars"; // $color: vars.$color; - Vars map[string]string + Vars map[string]any } func decodeOptions(m map[string]any) (opts Options, err error) { diff --git a/resources/resource_transformers/tocss/dartsass/integration_test.go b/resources/resource_transformers/tocss/dartsass/integration_test.go index e7ddd6e6f..e7432f12b 100644 --- a/resources/resource_transformers/tocss/dartsass/integration_test.go +++ b/resources/resource_transformers/tocss/dartsass/integration_test.go @@ -387,6 +387,10 @@ color_hsl = "hsl(0, 0%, 100%)" dimension = "24px" percentage = "10%" flex = "5fr" +name = "Hugo" +url = "https://gohugo.io" +integer = 32 +float = 3.14 -- assets/scss/main.scss -- @use "hugo:vars"; @use "sass:meta"; @@ -397,8 +401,15 @@ flex = "5fr" @debug meta.type-of(vars.$dimension); @debug meta.type-of(vars.$percentage); @debug meta.type-of(vars.$flex); +@debug meta.type-of(vars.$name); +@debug meta.type-of(vars.$url); +@debug meta.type-of(vars.$not_a_number); +@debug meta.type-of(vars.$integer); +@debug meta.type-of(vars.$float); +@debug meta.type-of(vars.$a_number); -- layouts/index.html -- {{ $vars := site.Params.sassvars}} +{{ $vars = merge $vars (dict "not_a_number" ("32xxx" | css.Quoted) "a_number" ("234" | css.Unquoted) )}} {{ $cssOpts := (dict "transpiler" "dartsass" "vars" $vars ) }} {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }} T1: {{ $r.Content }} @@ -418,5 +429,11 @@ T1: {{ $r.Content }} b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:6:0: number`) b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:7:0: number`) b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:8:0: number`) + b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:9:0: string`) + b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:10:0: string`) + b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:11:0: string`) + b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:12:0: number`) + b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:13:0: number`) + b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:14:0: number`) } diff --git a/resources/resource_transformers/tocss/internal/sass/cssValues.go b/resources/resource_transformers/tocss/internal/sass/cssValues.go index b23c4fc02..410e89e04 100644 --- a/resources/resource_transformers/tocss/internal/sass/cssValues.go +++ b/resources/resource_transformers/tocss/internal/sass/cssValues.go @@ -15,65 +15,67 @@ package sass type cssValue struct { prefix []string - sufix []string + suffix []string } var ( cssValues = cssValue{ + // https://developer.mozilla.org/en-US/docs/Web/CSS/color_value prefix: []string{ "#", - "rgb(", + "attr(", + "calc(", + "clamp(", "hsl(", "hwb(", - "lch(", "lab(", - "calc(", - "min(", + "lch(", "max(", + "min(", "minmax(", - "clamp(", - "attr(", + "rgb(", }, - sufix: []string{ - "em", - "ex", + // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Values_and_Units#dimensions + suffix: []string{ + "%", "cap", "ch", - "ic", - "rem", - "lh", - "rlh", - "vw", - "vh", - "vi", - "vb", - "vmin", - "vmax", - "cqw", + "cm", + "cqb", "cqh", "cqi", - "cqb", - "cqmin", "cqmax", - "cm", - "mm", - "Q", + "cqmin", + "cqw", + "deg", + "dpcm", + "dpi", + "dppx", + "em", + "ex", + "fr", + "grad", + "ic", "in", + "lh", + "mm", + "ms", "pc", "pt", "px", - "deg", - "grad", + "Q", "rad", - "turn", + "rem", + "rlh", "s", - "ms", - "fr", - "dpi", - "dpcm", - "dppx", + "turn", + "vb", + "vh", + "vi", + "vmax", + "vmin", + "vw", "x", - "%", }, } ) diff --git a/resources/resource_transformers/tocss/internal/sass/helpers.go b/resources/resource_transformers/tocss/internal/sass/helpers.go index e6f246b7c..f04250157 100644 --- a/resources/resource_transformers/tocss/internal/sass/helpers.go +++ b/resources/resource_transformers/tocss/internal/sass/helpers.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Hugo Authors. All rights reserved. +// Copyright 2023 The Hugo Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,15 +15,18 @@ package sass import ( "fmt" + "regexp" "sort" "strings" + + "github.com/gohugoio/hugo/common/types/css" ) const ( HugoVarsNamespace = "hugo:vars" ) -func CreateVarsStyleSheet(vars map[string]string) string { +func CreateVarsStyleSheet(vars map[string]any) string { if vars == nil { return "" } @@ -35,35 +38,56 @@ func CreateVarsStyleSheet(vars map[string]string) string { if !strings.HasPrefix(k, "$") { prefix = "$" } - // These variables can be a combination of Sass identifiers (e.g. sans-serif), which - // should not be quoted, and URLs et, which should be quoted. - // unquote() is knowing what to do with each. - // Use quoteVar() to check if the variables should be quoted or not. - if quoteVar(v) { - varsSlice = append(varsSlice, fmt.Sprintf("%s%s: unquote(%q);", prefix, k, v)) - } else { - varsSlice = append(varsSlice, fmt.Sprintf("%s%s: %s;", prefix, k, v)) + + switch v.(type) { + case css.QuotedString: + // Marked by the user as a string that needs to be quoted. + varsSlice = append(varsSlice, fmt.Sprintf("%s%s: %q;", prefix, k, v)) + default: + if isTypedCSSValue(v) { + // E.g. 24px, 1.5rem, 10%, hsl(0, 0%, 100%), calc(24px + 36px), #fff, #ffffff. + varsSlice = append(varsSlice, fmt.Sprintf("%s%s: %v;", prefix, k, v)) + } else { + // unquote will preserve quotes around URLs etc. if needed. + varsSlice = append(varsSlice, fmt.Sprintf("%s%s: unquote(%q);", prefix, k, v)) + } } } sort.Strings(varsSlice) varsStylesheet = strings.Join(varsSlice, "\n") + fmt.Println(varsStylesheet) + + fmt.Println(varsStylesheet) + return varsStylesheet } -func quoteVar(v string) bool { - v = strings.Trim(v, "\"") - for _, p := range cssValues.prefix { - if strings.HasPrefix(v, p) { - return false +var ( + isCSSColor = regexp.MustCompile(`^#[0-9a-fA-F]{3,6}$`) + isCSSFunc = regexp.MustCompile(`^([a-zA-Z-]+)\(`) + isCSSUnit = regexp.MustCompile(`^([0-9]+)(\.[0-9]+)?([a-zA-Z-%]+)$`) +) + +// isTypedCSSValue returns true if the given string is a CSS value that +// we should preserve the type of, as in: Not wrap it in quotes. +func isTypedCSSValue(v any) bool { + switch s := v.(type) { + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, css.UnquotedString: + return true + case string: + if isCSSColor.MatchString(s) { + return true } - } - for _, s := range cssValues.sufix { - if strings.HasSuffix(v, s) { - return false + if isCSSFunc.MatchString(s) { + return true } + if isCSSUnit.MatchString(s) { + return true + } + } - return true + return false } diff --git a/resources/resource_transformers/tocss/internal/sass/helpers_test.go b/resources/resource_transformers/tocss/internal/sass/helpers_test.go new file mode 100644 index 000000000..56e73736e --- /dev/null +++ b/resources/resource_transformers/tocss/internal/sass/helpers_test.go @@ -0,0 +1,44 @@ +// Copyright 2023 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sass + +import ( + "testing" + + qt "github.com/frankban/quicktest" +) + +func TestIsUnquotedCSSValue(t *testing.T) { + c := qt.New(t) + + for _, test := range []struct { + in any + out bool + }{ + {"24px", true}, + {"1.5rem", true}, + {"10%", true}, + {"hsl(0, 0%, 100%)", true}, + {"calc(24px + 36px)", true}, + {"24xxx", true}, // a false positive. + {123, true}, + {123.12, true}, + {"#fff", true}, + {"#ffffff", true}, + {"#ffffffff", false}, + } { + c.Assert(isTypedCSSValue(test.in), qt.Equals, test.out) + } + +} diff --git a/resources/resource_transformers/tocss/scss/client.go b/resources/resource_transformers/tocss/scss/client.go index 0d027d888..2028163ff 100644 --- a/resources/resource_transformers/tocss/scss/client.go +++ b/resources/resource_transformers/tocss/scss/client.go @@ -63,7 +63,7 @@ type Options struct { // Vars will be available in 'hugo:vars', e.g: // @import "hugo:vars"; - Vars map[string]string + Vars map[string]any } func DecodeOptions(m map[string]any) (opts Options, err error) { |