pax_global_header00006660000000000000000000000064133727646730014534gustar00rootroot0000000000000052 comment=8fac1ac12f22df184f859af81c3c2a28e33370f6 go-tocss-0.6.0/000077500000000000000000000000001337276467300132755ustar00rootroot00000000000000go-tocss-0.6.0/.gitignore000066400000000000000000000003001337276467300152560ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out go-tocss-0.6.0/.travis.yml000066400000000000000000000010351337276467300154050ustar00rootroot00000000000000language: go sudo: false dist: trusty git: depth: false go: - 1.11 - tip os: - linux - osx - windows matrix: allow_failures: - go: tip fast_finish: true exclude: - os: windows go: tip install: - mkdir -p $HOME/src - mv $HOME/gopath/src/github.com/bep/go-tocss $HOME/src - export TRAVIS_BUILD_DIR=$HOME/src/go-tocss - cd $TRAVIS_BUILD_DIR script: - go test -race ./... before_install: - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then choco install mingw -y; export PATH=/c/tools/mingw64/bin:"$PATH"; fi go-tocss-0.6.0/LICENSE000066400000000000000000000020651337276467300143050ustar00rootroot00000000000000MIT License Copyright (c) 2018 Bjørn Erik Pedersen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. go-tocss-0.6.0/README.md000066400000000000000000000013501337276467300145530ustar00rootroot00000000000000 [![Build Status](https://travis-ci.org/bep/go-tocss.svg?branch=master)](https://travis-ci.org/bep/go-tocss) [![Go Report Card](https://goreportcard.com/badge/github.com/bep/go-tocss)](https://goreportcard.com/report/github.com/bep/go-tocss) This is currently a, hopefully, simple to use [LibSass](https://sass-lang.com/libsass) Go API. It uses the C bindings in [https://github.com/wellington/go-libsass/libs](https://github.com/wellington/go-libsass/tree/master/libs) to do the heavy lifting. The primary motivation for this project is to add `SCSS` support to [Hugo](https://gohugo.io/). It is has some generic `tocss` package names hoping that there will be a solid native Go implementation that can replace `LibSass` in the near future. go-tocss-0.6.0/go.mod000066400000000000000000000003701337276467300144030ustar00rootroot00000000000000module github.com/bep/go-tocss require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 github.com/wellington/go-libsass v0.9.3-0.20181113175235-c63644206701 ) go-tocss-0.6.0/go.sum000066400000000000000000000013741337276467300144350ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/wellington/go-libsass v0.9.3-0.20181113175235-c63644206701 h1:9vG9vvVNVupO4Y7uwFkRgIMNe9rdaJMCINDe8vhAhLo= github.com/wellington/go-libsass v0.9.3-0.20181113175235-c63644206701/go.mod h1:mxgxgam0N0E+NAUMHLcu20Ccfc3mVpDkyrLDayqfiTs= go-tocss-0.6.0/scss/000077500000000000000000000000001337276467300142505ustar00rootroot00000000000000go-tocss-0.6.0/scss/common.go000066400000000000000000000050541337276467300160730ustar00rootroot00000000000000// Copyright © 2018 Bjørn Erik Pedersen . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. // Package scss provides options for SCSS transpilers. Note that there are no // current pure Go SASS implementation, so the only option is CGO and LibSASS. // But hopefully, fingers crossed, this will happen. package scss import ( "encoding/json" "fmt" "strings" ) type ( OutputStyle int ) const ( NestedStyle OutputStyle = iota ExpandedStyle CompactStyle CompressedStyle ) const ( nestedStyleStr = "nested" expandedStyleStr = "expanded" compactStyleStr = "compact" compressedStyleStr = "compressed" ) var outputStyleFromString = map[string]OutputStyle{ nestedStyleStr: NestedStyle, expandedStyleStr: ExpandedStyle, compactStyleStr: CompactStyle, compressedStyleStr: CompressedStyle, } var outputStyleToString = map[OutputStyle]string{ NestedStyle: nestedStyleStr, ExpandedStyle: expandedStyleStr, CompactStyle: compactStyleStr, CompressedStyle: compressedStyleStr, } func OutputStyleFromString(style string) OutputStyle { os, found := outputStyleFromString[strings.ToLower(style)] if found { return os } return NestedStyle } func OutputStyleToString(style OutputStyle) string { os, found := outputStyleToString[style] if found { return os } return nestedStyleStr } 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 // Source map settings SourceMapFilename string SourceMapRoot string InputPath string OutputPath string SourceMapContents bool OmitSourceMapURL bool EnableEmbeddedSourceMap bool } func JSONToError(jsonstr string) (e Error) { if err := json.Unmarshal([]byte(jsonstr), &e); err != nil { e.Message = "unknown error" } 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) } go-tocss-0.6.0/scss/common_test.go000066400000000000000000000021671337276467300171340ustar00rootroot00000000000000// Copyright © 2018 Bjørn Erik Pedersen . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. // Package scss provides options for SCSS transpilers. Note that there are no // current pure Go SASS implementation, so the only option is CGO and LibSASS. // But hopefully, fingers crossed, this will happen. package scss import ( "testing" "github.com/stretchr/testify/require" ) func TestOutputStyle(t *testing.T) { assert := require.New(t) assert.Equal(NestedStyle, OutputStyleFromString("nested")) assert.Equal(ExpandedStyle, OutputStyleFromString("expanded")) assert.Equal(CompactStyle, OutputStyleFromString("compact")) assert.Equal(CompressedStyle, OutputStyleFromString("compressed")) assert.Equal(NestedStyle, OutputStyleFromString("moo")) assert.Equal("nested", OutputStyleToString(NestedStyle)) assert.Equal("expanded", OutputStyleToString(ExpandedStyle)) assert.Equal("compact", OutputStyleToString(CompactStyle)) assert.Equal("compressed", OutputStyleToString(CompressedStyle)) assert.Equal("nested", OutputStyleToString(43)) } go-tocss-0.6.0/scss/libsass/000077500000000000000000000000001337276467300157105ustar00rootroot00000000000000go-tocss-0.6.0/scss/libsass/transpiler.go000066400000000000000000000062211337276467300204230ustar00rootroot00000000000000// Copyright © 2018 Bjørn Erik Pedersen . // // 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 github.com/wellington/go-libsass/libs. package libsass import ( "bytes" "io" "io/ioutil" "os" "strings" "github.com/bep/go-tocss/scss" "github.com/bep/go-tocss/tocss" "github.com/wellington/go-libsass/libs" ) type libsassTranspiler struct { options scss.Options } // New creates a new libsass transpiler configured with the given options. func New(options scss.Options) (tocss.Transpiler, error) { return &libsassTranspiler{options: options}, nil } // Execute transpiles the SCSS from src into dst. Note that you can import // older SASS (.sass) files, but the main entry (src) currently needs to be SCSS. func (t *libsassTranspiler) Execute(dst io.Writer, src io.Reader) (tocss.Result, error) { var result tocss.Result var sourceStr string if t.options.SassSyntax { // LibSass does not support this directly, so have to handle the main SASS content // special. var buf bytes.Buffer err := libs.ToScss(src, &buf) if err != nil { return result, err } sourceStr = buf.String() } else { b, err := ioutil.ReadAll(src) if err != nil { return result, err } sourceStr = string(b) } dataCtx := libs.SassMakeDataContext(sourceStr) opts := libs.SassDataContextGetOptions(dataCtx) { // Set options if t.options.ImportResolver != nil { idx := libs.BindImporter(opts, t.options.ImportResolver) defer libs.RemoveImporter(idx) } if t.options.Precision != 0 { libs.SassOptionSetPrecision(opts, t.options.Precision) } if t.options.SourceMapFilename != "" { libs.SassOptionSetSourceMapFile(opts, t.options.SourceMapFilename) } if t.options.SourceMapRoot != "" { libs.SassOptionSetSourceMapRoot(opts, t.options.SourceMapRoot) } if t.options.OutputPath != "" { libs.SassOptionSetOutputPath(opts, t.options.OutputPath) } if t.options.InputPath != "" { libs.SassOptionSetInputPath(opts, t.options.InputPath) } libs.SassOptionSetSourceMapContents(opts, t.options.SourceMapContents) libs.SassOptionSetOmitSourceMapURL(opts, t.options.OmitSourceMapURL) libs.SassOptionSetSourceMapEmbed(opts, t.options.EnableEmbeddedSourceMap) libs.SassOptionSetIncludePath(opts, strings.Join(t.options.IncludePaths, string(os.PathListSeparator))) libs.SassOptionSetOutputStyle(opts, int(t.options.OutputStyle)) libs.SassOptionSetSourceComments(opts, false) libs.SassDataContextSetOptions(dataCtx, opts) } ctx := libs.SassDataContextGetContext(dataCtx) compiler := libs.SassMakeDataCompiler(dataCtx) libs.SassCompilerParse(compiler) libs.SassCompilerExecute(compiler) defer libs.SassDeleteCompiler(compiler) outputString := libs.SassContextGetOutputString(ctx) io.WriteString(dst, outputString) if status := libs.SassContextGetErrorStatus(ctx); status != 0 { return result, scss.JSONToError(libs.SassContextGetErrorJSON(ctx)) } result.SourceMapFilename = libs.SassOptionGetSourceMapFile(opts) result.SourceMapContent = libs.SassContextGetSourceMapString(ctx) return result, nil } go-tocss-0.6.0/scss/libsass/transpiler_test.go000066400000000000000000000102351337276467300214620ustar00rootroot00000000000000// Copyright © 2018 Bjørn Erik Pedersen . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. package libsass import ( "bytes" "io/ioutil" "os" "path/filepath" "sync" "testing" "github.com/bep/go-tocss/scss" "github.com/stretchr/testify/require" ) func TestWithImportResolver(t *testing.T) { assert := require.New(t) src := bytes.NewBufferString(` @import "colors"; div { p { color: $white; } }`) var dst bytes.Buffer importResolver := func(url string, prev string) (string, string, bool) { // This will make every import the same, which is probably not a common use // case. return url, `$white: #fff`, true } transpiler, err := New(scss.Options{ImportResolver: importResolver}) assert.NoError(err) _, err = transpiler.Execute(&dst, src) assert.NoError(err) assert.Equal("div p {\n color: #fff; }\n", dst.String()) } func TestSassSyntax(t *testing.T) { assert := require.New(t) src := bytes.NewBufferString(` $color: #333; .content-navigation border-color: $color `) var dst bytes.Buffer transpiler, err := New(scss.Options{OutputStyle: scss.CompressedStyle, SassSyntax: true}) assert.NoError(err) _, err = transpiler.Execute(&dst, src) assert.NoError(err) assert.Equal(".content-navigation{border-color:#333}\n", dst.String()) } func TestOutputStyle(t *testing.T) { assert := require.New(t) src := bytes.NewBufferString(` div { p { color: #ccc; } }`) var dst bytes.Buffer transpiler, err := New(scss.Options{OutputStyle: scss.CompressedStyle}) assert.NoError(err) _, err = transpiler.Execute(&dst, src) assert.NoError(err) assert.Equal("div p{color:#ccc}\n", dst.String()) } func TestSourceMapSettings(t *testing.T) { dir, _ := ioutil.TempDir(os.TempDir(), "tocss") defer os.RemoveAll(dir) colors := filepath.Join(dir, "_colors.scss") ioutil.WriteFile(colors, []byte(` $moo: #f442d1 !default; `), 0755) assert := require.New(t) src := bytes.NewBufferString(` @import "colors"; div { p { color: $moo; } }`) var dst bytes.Buffer transpiler, err := New(scss.Options{ IncludePaths: []string{dir}, EnableEmbeddedSourceMap: false, SourceMapContents: true, OmitSourceMapURL: false, SourceMapFilename: "source.map", OutputPath: "outout.css", InputPath: "input.scss", SourceMapRoot: "/my/root", }) assert.NoError(err) result, err := transpiler.Execute(&dst, src) assert.NoError(err) assert.Equal("div p {\n color: #f442d1; }\n\n/*# sourceMappingURL=source.map */", dst.String()) assert.Equal("source.map", result.SourceMapFilename) assert.Contains(result.SourceMapContent, `"sourceRoot": "/my/root",`) assert.Contains(result.SourceMapContent, `"file": "outout.css",`) assert.Contains(result.SourceMapContent, `"input.scss",`) assert.Contains(result.SourceMapContent, `mappings": "AAGA,AAAM,GAAH,CAAG,CAAC,CAAC;EAAE,KAAK,ECFH,OAAO,GDEM"`) } func TestConcurrentTranspile(t *testing.T) { assert := require.New(t) importResolver := func(url string, prev string) (string, string, bool) { return url, `$white: #fff`, true } transpiler, err := New(scss.Options{ OutputStyle: scss.CompressedStyle, ImportResolver: importResolver}) assert.NoError(err) var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() for j := 0; j < 10; j++ { src := bytes.NewBufferString(` @import "colors"; div { p { color: $white; } }`) var dst bytes.Buffer _, err := transpiler.Execute(&dst, src) assert.NoError(err) assert.Equal("div p{color:#fff}\n", dst.String()) } }() } wg.Wait() } // 3000 397942 ns/op 2192 B/op 4 allocs/op func BenchmarkTranspile(b *testing.B) { srcs := `div { p { color: #ccc; } }` var src, dst bytes.Buffer transpiler, err := New(scss.Options{OutputStyle: scss.CompressedStyle}) if err != nil { b.Fatal(err) } b.ResetTimer() for n := 0; n < b.N; n++ { src.Reset() dst.Reset() src.WriteString(srcs) if _, err := transpiler.Execute(&dst, &src); err != nil { b.Fatal(err) } if dst.String() != "div p{color:#ccc}\n" { b.Fatal("Got:", dst.String()) } } } go-tocss-0.6.0/tocss/000077500000000000000000000000001337276467300144305ustar00rootroot00000000000000go-tocss-0.6.0/tocss/transpiler.go000066400000000000000000000007601337276467300171450ustar00rootroot00000000000000// Copyright © 2018 Bjørn Erik Pedersen . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. // Package tocss provides the common API for tranpilation of the source // to CSS. package tocss import ( "io" ) type Result struct { // If source maps are configured. SourceMapFilename string SourceMapContent string } type Transpiler interface { Execute(dst io.Writer, src io.Reader) (Result, error) }