github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/resources/resource_transformers/tocss/dartsass/transform.go (about) 1 // Copyright 2022 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package dartsass 15 16 import ( 17 "fmt" 18 "io" 19 "path" 20 "path/filepath" 21 "strings" 22 23 "github.com/gohugoio/hugo/common/hugo" 24 "github.com/gohugoio/hugo/common/paths" 25 "github.com/gohugoio/hugo/htesting" 26 "github.com/gohugoio/hugo/media" 27 28 "github.com/gohugoio/hugo/resources" 29 30 "github.com/gohugoio/hugo/resources/internal" 31 "github.com/gohugoio/hugo/resources/resource_transformers/tocss/internal/sass" 32 33 "github.com/spf13/afero" 34 35 "github.com/gohugoio/hugo/hugofs" 36 37 godartsassv1 "github.com/bep/godartsass" 38 "github.com/bep/godartsass/v2" 39 ) 40 41 // Supports returns whether dart-sass-embedded is found in $PATH. 42 func Supports() bool { 43 if htesting.SupportsAll() { 44 return true 45 } 46 return hugo.DartSassBinaryName != "" 47 } 48 49 type transform struct { 50 optsm map[string]any 51 c *Client 52 } 53 54 func (t *transform) Key() internal.ResourceTransformationKey { 55 return internal.NewResourceTransformationKey(transformationName, t.optsm) 56 } 57 58 func (t *transform) Transform(ctx *resources.ResourceTransformationCtx) error { 59 ctx.OutMediaType = media.Builtin.CSSType 60 61 opts, err := decodeOptions(t.optsm) 62 if err != nil { 63 return err 64 } 65 66 if opts.TargetPath != "" { 67 ctx.OutPath = opts.TargetPath 68 } else { 69 ctx.ReplaceOutPathExtension(".css") 70 } 71 72 baseDir := path.Dir(ctx.SourcePath) 73 filename := dartSassStdinPrefix 74 75 if ctx.SourcePath != "" { 76 filename += t.c.sfs.RealFilename(ctx.SourcePath) 77 } 78 79 args := godartsass.Args{ 80 URL: filename, 81 IncludePaths: t.c.sfs.RealDirs(baseDir), 82 ImportResolver: importResolver{ 83 baseDir: baseDir, 84 c: t.c, 85 86 varsStylesheet: godartsass.Import{Content: sass.CreateVarsStyleSheet(opts.Vars)}, 87 }, 88 OutputStyle: godartsass.ParseOutputStyle(opts.OutputStyle), 89 EnableSourceMap: opts.EnableSourceMap, 90 SourceMapIncludeSources: opts.SourceMapIncludeSources, 91 } 92 93 // Append any workDir relative include paths 94 for _, ip := range opts.IncludePaths { 95 info, err := t.c.workFs.Stat(filepath.Clean(ip)) 96 if err == nil { 97 filename := info.(hugofs.FileMetaInfo).Meta().Filename 98 args.IncludePaths = append(args.IncludePaths, filename) 99 } 100 } 101 102 if ctx.InMediaType.SubType == media.Builtin.SASSType.SubType { 103 args.SourceSyntax = godartsass.SourceSyntaxSASS 104 } 105 106 res, err := t.c.toCSS(args, ctx.From) 107 if err != nil { 108 return err 109 } 110 111 out := res.CSS 112 113 _, err = io.WriteString(ctx.To, out) 114 if err != nil { 115 return err 116 } 117 118 if opts.EnableSourceMap && res.SourceMap != "" { 119 if err := ctx.PublishSourceMap(res.SourceMap); err != nil { 120 return err 121 } 122 _, err = fmt.Fprintf(ctx.To, "\n\n/*# sourceMappingURL=%s */", path.Base(ctx.OutPath)+".map") 123 } 124 125 return err 126 } 127 128 type importResolver struct { 129 baseDir string 130 c *Client 131 132 varsStylesheet godartsass.Import 133 } 134 135 func (t importResolver) CanonicalizeURL(url string) (string, error) { 136 if url == sass.HugoVarsNamespace { 137 return url, nil 138 } 139 filePath, isURL := paths.UrlToFilename(url) 140 var prevDir string 141 var pathDir string 142 if isURL { 143 var found bool 144 prevDir, found = t.c.sfs.MakePathRelative(filepath.Dir(filePath)) 145 146 if !found { 147 // Not a member of this filesystem, let Dart Sass handle it. 148 return "", nil 149 } 150 } else { 151 prevDir = t.baseDir 152 pathDir = path.Dir(url) 153 } 154 155 basePath := filepath.Join(prevDir, pathDir) 156 name := filepath.Base(filePath) 157 158 // Pick the first match. 159 var namePatterns []string 160 if strings.Contains(name, ".") { 161 namePatterns = []string{"_%s", "%s"} 162 } else if strings.HasPrefix(name, "_") { 163 namePatterns = []string{"_%s.scss", "_%s.sass", "_%s.css"} 164 } else { 165 namePatterns = []string{"_%s.scss", "%s.scss", "_%s.sass", "%s.sass", "_%s.css", "%s.css"} 166 } 167 168 name = strings.TrimPrefix(name, "_") 169 170 for _, namePattern := range namePatterns { 171 filenameToCheck := filepath.Join(basePath, fmt.Sprintf(namePattern, name)) 172 fi, err := t.c.sfs.Fs.Stat(filenameToCheck) 173 if err == nil { 174 if fim, ok := fi.(hugofs.FileMetaInfo); ok { 175 return "file://" + filepath.ToSlash(fim.Meta().Filename), nil 176 } 177 } 178 } 179 180 // Not found, let Dart Dass handle it 181 return "", nil 182 } 183 184 func (t importResolver) Load(url string) (godartsass.Import, error) { 185 if url == sass.HugoVarsNamespace { 186 return t.varsStylesheet, nil 187 } 188 filename, _ := paths.UrlToFilename(url) 189 b, err := afero.ReadFile(hugofs.Os, filename) 190 191 sourceSyntax := godartsass.SourceSyntaxSCSS 192 if strings.HasSuffix(filename, ".sass") { 193 sourceSyntax = godartsass.SourceSyntaxSASS 194 } else if strings.HasSuffix(filename, ".css") { 195 sourceSyntax = godartsass.SourceSyntaxCSS 196 } 197 198 return godartsass.Import{Content: string(b), SourceSyntax: sourceSyntax}, err 199 200 } 201 202 type importResolverV1 struct { 203 godartsass.ImportResolver 204 } 205 206 func (t importResolverV1) Load(url string) (godartsassv1.Import, error) { 207 res, err := t.ImportResolver.Load(url) 208 return godartsassv1.Import{Content: res.Content, SourceSyntax: godartsassv1.SourceSyntax(res.SourceSyntax)}, err 209 }