URI: 
       resources: Address Dart Sass deprecation of global built-in functions - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 889308dd854b0907069d7bc6dd44ed760bc6e819
   DIR parent 72352f205afeef8310dcc276fc7a72db311a1621
  HTML Author: Joe Mooring <joe.mooring@veriphor.com>
       Date:   Fri, 18 Oct 2024 16:10:46 -0700
       
       resources: Address Dart Sass deprecation of global built-in functions
       
       See https://github.com/sass/dart-sass/releases/tag/1.80.0
       
       Fixes #12961
       
       Diffstat:
         M resources/resource_transformers/to… |       4 ++--
         D resources/resource_transformers/to… |      87 -------------------------------
         A resources/resource_transformers/to… |     102 +++++++++++++++++++++++++++++++
         R resources/resource_transformers/to… |       0 
         M resources/resource_transformers/to… |       4 ++--
         M tpl/css/css.go                      |      17 +++++------------
         M tpl/resources/resources_integratio… |      44 +++++++++++++++++++++++++++++++
       
       7 files changed, 155 insertions(+), 103 deletions(-)
       ---
   DIR diff --git a/resources/resource_transformers/tocss/dartsass/transform.go b/resources/resource_transformers/tocss/dartsass/transform.go
       @@ -29,7 +29,7 @@ import (
                "github.com/gohugoio/hugo/resources"
        
                "github.com/gohugoio/hugo/resources/internal"
       -        "github.com/gohugoio/hugo/resources/resource_transformers/tocss/internal/sass"
       +        "github.com/gohugoio/hugo/resources/resource_transformers/tocss/sass"
        
                "github.com/spf13/afero"
        
       @@ -85,7 +85,7 @@ func (t *transform) Transform(ctx *resources.ResourceTransformationCtx) error {
                                c:                 t.c,
                                dependencyManager: ctx.DependencyManager,
        
       -                        varsStylesheet: godartsass.Import{Content: sass.CreateVarsStyleSheet(opts.Vars)},
       +                        varsStylesheet: godartsass.Import{Content: sass.CreateVarsStyleSheet(sass.TranspilerDart, opts.Vars)},
                        },
                        OutputStyle:             godartsass.ParseOutputStyle(opts.OutputStyle),
                        EnableSourceMap:         opts.EnableSourceMap,
   DIR diff --git a/resources/resource_transformers/tocss/internal/sass/helpers.go b/resources/resource_transformers/tocss/internal/sass/helpers.go
       @@ -1,87 +0,0 @@
       -// Copyright 2024 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 (
       -        "fmt"
       -        "regexp"
       -        "sort"
       -        "strings"
       -
       -        "github.com/gohugoio/hugo/common/types/css"
       -)
       -
       -const (
       -        HugoVarsNamespace = "hugo:vars"
       -)
       -
       -func CreateVarsStyleSheet(vars map[string]any) string {
       -        if vars == nil {
       -                return ""
       -        }
       -        var varsStylesheet string
       -
       -        var varsSlice []string
       -        for k, v := range vars {
       -                var prefix string
       -                if !strings.HasPrefix(k, "$") {
       -                        prefix = "$"
       -                }
       -
       -                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")
       -        return varsStylesheet
       -}
       -
       -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
       -                }
       -                if isCSSFunc.MatchString(s) {
       -                        return true
       -                }
       -                if isCSSUnit.MatchString(s) {
       -                        return true
       -                }
       -
       -        }
       -
       -        return false
       -}
   DIR diff --git a/resources/resource_transformers/tocss/sass/helpers.go b/resources/resource_transformers/tocss/sass/helpers.go
       @@ -0,0 +1,102 @@
       +// Copyright 2024 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 (
       +        "fmt"
       +        "regexp"
       +        "sort"
       +        "strings"
       +
       +        "github.com/gohugoio/hugo/common/types/css"
       +)
       +
       +const (
       +        HugoVarsNamespace = "hugo:vars"
       +        // Transpiler implementation can be controlled from the client by
       +        // setting the 'transpiler' option.
       +        // Default is currently 'libsass', but that may change.
       +        TranspilerDart    = "dartsass"
       +        TranspilerLibSass = "libsass"
       +)
       +
       +func CreateVarsStyleSheet(transpiler string, vars map[string]any) string {
       +        if vars == nil {
       +                return ""
       +        }
       +        var varsStylesheet string
       +
       +        var varsSlice []string
       +        for k, v := range vars {
       +                var prefix string
       +                if !strings.HasPrefix(k, "$") {
       +                        prefix = "$"
       +                }
       +
       +                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.
       +                                if transpiler == TranspilerDart {
       +                                        varsSlice = append(varsSlice, fmt.Sprintf("%s%s: string.unquote(%q);", prefix, k, v))
       +                                } else {
       +                                        varsSlice = append(varsSlice, fmt.Sprintf("%s%s: unquote(%q);", prefix, k, v))
       +                                }
       +                        }
       +                }
       +        }
       +        sort.Strings(varsSlice)
       +
       +        if transpiler == TranspilerDart {
       +                varsStylesheet = `@use "sass:string";` + "\n" + strings.Join(varsSlice, "\n")
       +        } else {
       +                varsStylesheet = strings.Join(varsSlice, "\n")
       +        }
       +
       +        return varsStylesheet
       +}
       +
       +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
       +                }
       +                if isCSSFunc.MatchString(s) {
       +                        return true
       +                }
       +                if isCSSUnit.MatchString(s) {
       +                        return true
       +                }
       +
       +        }
       +
       +        return false
       +}
   DIR diff --git a/resources/resource_transformers/tocss/internal/sass/helpers_test.go b/resources/resource_transformers/tocss/sass/helpers_test.go
   DIR diff --git a/resources/resource_transformers/tocss/scss/tocss.go b/resources/resource_transformers/tocss/scss/tocss.go
       @@ -31,7 +31,7 @@ import (
                "github.com/gohugoio/hugo/identity"
                "github.com/gohugoio/hugo/media"
                "github.com/gohugoio/hugo/resources"
       -        "github.com/gohugoio/hugo/resources/resource_transformers/tocss/internal/sass"
       +        "github.com/gohugoio/hugo/resources/resource_transformers/tocss/sass"
        )
        
        // Used in tests. This feature requires Hugo to be built with the extended tag.
       @@ -64,7 +64,7 @@ func (t *toCSSTransformation) Transform(ctx *resources.ResourceTransformationCtx
                        }
                }
        
       -        varsStylesheet := sass.CreateVarsStyleSheet(options.from.Vars)
       +        varsStylesheet := sass.CreateVarsStyleSheet(sass.TranspilerLibSass, options.from.Vars)
        
                // To allow for overrides of SCSS files anywhere in the project/theme hierarchy, we need
                // to help libsass revolve the filename by looking in the composite filesystem first.
   DIR diff --git a/tpl/css/css.go b/tpl/css/css.go
       @@ -15,6 +15,7 @@ import (
                "github.com/gohugoio/hugo/resources/resource_transformers/babel"
                "github.com/gohugoio/hugo/resources/resource_transformers/cssjs"
                "github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass"
       +        "github.com/gohugoio/hugo/resources/resource_transformers/tocss/sass"
                "github.com/gohugoio/hugo/resources/resource_transformers/tocss/scss"
                "github.com/gohugoio/hugo/tpl/internal"
                "github.com/gohugoio/hugo/tpl/internal/resourcehelpers"
       @@ -84,21 +85,13 @@ func (ns *Namespace) Sass(args ...any) (resource.Resource, error) {
                        return nil, errors.New("must not provide more arguments than resource object and options")
                }
        
       -        const (
       -                // Transpiler implementation can be controlled from the client by
       -                // setting the 'transpiler' option.
       -                // Default is currently 'libsass', but that may change.
       -                transpilerDart    = "dartsass"
       -                transpilerLibSass = "libsass"
       -        )
       -
                var (
                        r          resources.ResourceTransformer
                        m          map[string]any
                        targetPath string
                        err        error
                        ok         bool
       -                transpiler = transpilerLibSass
       +                transpiler = sass.TranspilerLibSass
                )
        
                r, targetPath, ok = resourcehelpers.ResolveIfFirstArgIsString(args)
       @@ -113,15 +106,15 @@ func (ns *Namespace) Sass(args ...any) (resource.Resource, error) {
                if m != nil {
                        if t, _, found := maps.LookupEqualFold(m, "transpiler"); found {
                                switch t {
       -                        case transpilerDart, transpilerLibSass:
       +                        case sass.TranspilerDart, sass.TranspilerLibSass:
                                        transpiler = cast.ToString(t)
                                default:
       -                                return nil, fmt.Errorf("unsupported transpiler %q; valid values are %q or %q", t, transpilerLibSass, transpilerDart)
       +                                return nil, fmt.Errorf("unsupported transpiler %q; valid values are %q or %q", t, sass.TranspilerLibSass, sass.TranspilerDart)
                                }
                        }
                }
        
       -        if transpiler == transpilerLibSass {
       +        if transpiler == sass.TranspilerLibSass {
                        var options scss.Options
                        if targetPath != "" {
                                options.TargetPath = paths.ToSlashTrimLeading(targetPath)
   DIR diff --git a/tpl/resources/resources_integration_test.go b/tpl/resources/resources_integration_test.go
       @@ -18,6 +18,8 @@ import (
        
                qt "github.com/frankban/quicktest"
                "github.com/gohugoio/hugo/hugolib"
       +        "github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass"
       +        "github.com/gohugoio/hugo/resources/resource_transformers/tocss/scss"
        )
        
        func TestCopy(t *testing.T) {
       @@ -238,3 +240,45 @@ match /files/C*: 2|
                b.AssertFileContent("public/files/b.txt", "I am b.txt")
                b.AssertFileContent("public/files/C.txt", "I am C.txt")
        }
       +
       +// Issue #12961
       +func TestDartSassVars(t *testing.T) {
       +        t.Parallel()
       +
       +        if !scss.Supports() || !dartsass.Supports() {
       +                t.Skip()
       +        }
       +
       +        files := `
       +-- hugo.toml --
       +disableKinds = ['page','section','rss','sitemap','taxonomy','term']
       +-- layouts/index.html --
       +{{ $opts := dict "transpiler" "dartsass" "outputStyle" "compressed" "vars" (dict "color" "red") }}
       +{{ with resources.Get "dartsass.scss" | css.Sass $opts }}
       +  {{ .Content }}
       +{{ end }}
       +
       +{{ $opts := dict "transpiler" "libsass" "outputStyle" "compressed" "vars" (dict "color" "blue") }}
       +{{ with resources.Get "libsass.scss" | css.Sass $opts }}
       +  {{ .Content }}
       +{{ end }}
       +-- assets/dartsass.scss --
       +@use "hugo:vars" as v;
       +.dartsass {
       +  color: v.$color;
       +}
       +-- assets/libsass.scss --
       +@import "hugo:vars";
       +.libsass {
       +  color: $color;
       +}
       +`
       +
       +        b := hugolib.Test(t, files, hugolib.TestOptWarn())
       +
       +        b.AssertFileContent("public/index.html",
       +                ".dartsass{color:red}",
       +                ".libsass{color:blue}",
       +        )
       +        b.AssertLogContains("! WARN  Dart Sass: hugo:vars")
       +}