SandpointsGitHook/vendor/github.com/bep/golibsass/libsass/transpiler.go

178 lines
4.6 KiB
Go

// Copyright © 2020 Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// Package libsass a SCSS transpiler to CSS using LibSASS.
package libsass
import (
"encoding/json"
"fmt"
"os"
"strings"
"github.com/bep/golibsass/internal/libsass"
)
type libsassTranspiler struct {
options Options
}
// New creates a new libsass transpiler configured with the given options.
func New(options Options) (Transpiler, error) {
return libsassTranspiler{options: options}, nil
}
// Execute transpiles the SCSS or SASS from src into dst.
func (t libsassTranspiler) Execute(src string) (Result, error) {
var result Result
if t.options.SassSyntax {
// LibSass does not support this directly, so have to handle the main SASS content
// special.
src = libsass.SassToScss(src)
}
dataCtx := libsass.SassMakeDataContext(src)
opts := libsass.SassDataContextGetOptions(dataCtx)
{
// Set options
if t.options.ImportResolver != nil {
idx := libsass.AddImportResolver(opts, t.options.ImportResolver)
defer libsass.DeleteImportResolver(idx)
}
if t.options.Precision != 0 {
libsass.SassOptionSetPrecision(opts, t.options.Precision)
}
if t.options.SourceMapOptions.Filename != "" {
libsass.SassOptionSetSourceMapFile(opts, t.options.SourceMapOptions.Filename)
}
if t.options.SourceMapOptions.Root != "" {
libsass.SassOptionSetSourceMapRoot(opts, t.options.SourceMapOptions.Root)
}
if t.options.SourceMapOptions.OutputPath != "" {
libsass.SassOptionSetOutputPath(opts, t.options.SourceMapOptions.OutputPath)
}
if t.options.SourceMapOptions.InputPath != "" {
libsass.SassOptionSetInputPath(opts, t.options.SourceMapOptions.InputPath)
}
libsass.SassOptionSetSourceMapContents(opts, t.options.SourceMapOptions.Contents)
libsass.SassOptionSetOmitSourceMapURL(opts, t.options.SourceMapOptions.OmitURL)
libsass.SassOptionSetSourceMapEmbed(opts, t.options.SourceMapOptions.EnableEmbedded)
libsass.SassOptionSetIncludePath(opts, strings.Join(t.options.IncludePaths, string(os.PathListSeparator)))
libsass.SassOptionSetOutputStyle(opts, int(t.options.OutputStyle))
libsass.SassOptionSetSourceComments(opts, false)
libsass.SassDataContextSetOptions(dataCtx, opts)
}
ctx := libsass.SassDataContextGetContext(dataCtx)
compiler := libsass.SassMakeDataCompiler(dataCtx)
defer libsass.SassDeleteCompiler(compiler)
libsass.SassCompilerParse(compiler)
libsass.SassCompilerExecute(compiler)
if status := libsass.SassContextGetErrorStatus(ctx); status != 0 {
return result, jsonToError(libsass.SassContextGetErrorJSON(ctx))
}
result.CSS = libsass.SassContextGetOutputString(ctx)
result.SourceMapFilename = libsass.SassOptionGetSourceMapFile(opts)
result.SourceMapContent = libsass.SassContextGetSourceMapString(ctx)
return result, nil
}
type Result struct {
CSS string
// If source maps are configured.
SourceMapFilename string
SourceMapContent string
}
type Transpiler interface {
Execute(src string) (Result, error)
}
type (
OutputStyle int
)
const (
NestedStyle OutputStyle = iota
ExpandedStyle
CompactStyle
CompressedStyle
)
// ParseOutputStyle will convert s into OutputStyle.
// Case insensitive, returns NestedStyle for unknown values.
func ParseOutputStyle(s string) OutputStyle {
switch strings.ToLower(s) {
case "nested":
return NestedStyle
case "expanded":
return ExpandedStyle
case "compact":
return CompactStyle
case "compressed":
return CompressedStyle
}
return NestedStyle
}
type Options struct {
// Default is nested.
OutputStyle OutputStyle
// Precision of floating point math.
Precision int
// File paths to use to resolve imports.
IncludePaths []string
// ImportResolver can be used to supply a custom import resolver, both to redirect
// to another URL or to return the body.
ImportResolver func(url string, prev string) (newURL string, body string, resolved bool)
// Used to indicate "old style" SASS for the input stream.
SassSyntax bool
SourceMapOptions SourceMapOptions
}
type SourceMapOptions struct {
Filename string
Root string
InputPath string
OutputPath string
Contents bool
OmitURL bool
EnableEmbedded bool
}
func jsonToError(jsonstr string) (e Error) {
_ = json.Unmarshal([]byte(jsonstr), &e)
return
}
type Error struct {
Status int `json:"status"`
Column int `json:"column"`
File string `json:"file"`
Line int `json:"line"`
Message string `json:"message"`
}
func (e Error) Error() string {
return fmt.Sprintf("file %q, line %d, col %d: %s ", e.File, e.Line, e.Column, e.Message)
}