[67] | 1 | package gcss
|
---|
| 2 |
|
---|
| 3 | import (
|
---|
| 4 | "bytes"
|
---|
| 5 | "io"
|
---|
| 6 | "io/ioutil"
|
---|
| 7 | "path/filepath"
|
---|
| 8 | "strings"
|
---|
| 9 | )
|
---|
| 10 |
|
---|
| 11 | // extensions
|
---|
| 12 | const (
|
---|
| 13 | extCSS = ".css"
|
---|
| 14 | extGCSS = ".gcss"
|
---|
| 15 | )
|
---|
| 16 |
|
---|
| 17 | // cssFilePath converts path's extenstion into a CSS file extension.
|
---|
| 18 | var cssFilePath = func(path string) string {
|
---|
| 19 | return convertExt(path, extCSS)
|
---|
| 20 | }
|
---|
| 21 |
|
---|
| 22 | // Compile compiles GCSS data which is read from src and
|
---|
| 23 | // Writes the result CSS data to the dst.
|
---|
| 24 | func Compile(dst io.Writer, src io.Reader) (int, error) {
|
---|
| 25 | data, err := ioutil.ReadAll(src)
|
---|
| 26 |
|
---|
| 27 | if err != nil {
|
---|
| 28 | return 0, err
|
---|
| 29 | }
|
---|
| 30 |
|
---|
| 31 | bc, berrc := compileBytes(data)
|
---|
| 32 |
|
---|
| 33 | bf := new(bytes.Buffer)
|
---|
| 34 |
|
---|
| 35 | BufWriteLoop:
|
---|
| 36 | for {
|
---|
| 37 | select {
|
---|
| 38 | case b, ok := <-bc:
|
---|
| 39 | if !ok {
|
---|
| 40 | break BufWriteLoop
|
---|
| 41 | }
|
---|
| 42 |
|
---|
| 43 | bf.Write(b)
|
---|
| 44 | case err := <-berrc:
|
---|
| 45 | return 0, err
|
---|
| 46 | }
|
---|
| 47 | }
|
---|
| 48 |
|
---|
| 49 | return dst.Write(bf.Bytes())
|
---|
| 50 | }
|
---|
| 51 |
|
---|
| 52 | // CompileFile parses the GCSS file specified by the path parameter,
|
---|
| 53 | // generates a CSS file and returns the path of the generated CSS file
|
---|
| 54 | // and an error when it occurs.
|
---|
| 55 | func CompileFile(path string) (string, error) {
|
---|
| 56 | data, err := ioutil.ReadFile(path)
|
---|
| 57 |
|
---|
| 58 | if err != nil {
|
---|
| 59 | return "", err
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 | cssPath := cssFilePath(path)
|
---|
| 63 |
|
---|
| 64 | bc, berrc := compileBytes(data)
|
---|
| 65 |
|
---|
| 66 | done, werrc := write(cssPath, bc, berrc)
|
---|
| 67 |
|
---|
| 68 | select {
|
---|
| 69 | case <-done:
|
---|
| 70 | case err := <-werrc:
|
---|
| 71 | return "", err
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | return cssPath, nil
|
---|
| 75 | }
|
---|
| 76 |
|
---|
| 77 | // compileBytes parses the GCSS byte array passed as the s parameter,
|
---|
| 78 | // generates a CSS byte array and returns the two channels: the first
|
---|
| 79 | // one returns the CSS byte array and the last one returns an error
|
---|
| 80 | // when it occurs.
|
---|
| 81 | func compileBytes(b []byte) (<-chan []byte, <-chan error) {
|
---|
| 82 | lines := strings.Split(formatLF(string(b)), lf)
|
---|
| 83 |
|
---|
| 84 | bc := make(chan []byte, len(lines))
|
---|
| 85 | errc := make(chan error)
|
---|
| 86 |
|
---|
| 87 | go func() {
|
---|
| 88 | ctx := newContext()
|
---|
| 89 |
|
---|
| 90 | elemc, pErrc := parse(lines)
|
---|
| 91 |
|
---|
| 92 | for {
|
---|
| 93 | select {
|
---|
| 94 | case elem, ok := <-elemc:
|
---|
| 95 | if !ok {
|
---|
| 96 | close(bc)
|
---|
| 97 | return
|
---|
| 98 | }
|
---|
| 99 |
|
---|
| 100 | elem.SetContext(ctx)
|
---|
| 101 |
|
---|
| 102 | switch v := elem.(type) {
|
---|
| 103 | case *mixinDeclaration:
|
---|
| 104 | ctx.mixins[v.name] = v
|
---|
| 105 | case *variable:
|
---|
| 106 | ctx.vars[v.name] = v
|
---|
| 107 | case *atRule, *declaration, *selector:
|
---|
| 108 | bf := new(bytes.Buffer)
|
---|
| 109 | elem.WriteTo(bf)
|
---|
| 110 | bc <- bf.Bytes()
|
---|
| 111 | }
|
---|
| 112 | case err := <-pErrc:
|
---|
| 113 | errc <- err
|
---|
| 114 | return
|
---|
| 115 | }
|
---|
| 116 | }
|
---|
| 117 | }()
|
---|
| 118 |
|
---|
| 119 | return bc, errc
|
---|
| 120 | }
|
---|
| 121 |
|
---|
| 122 | // Path converts path's extenstion into a GCSS file extension.
|
---|
| 123 | func Path(path string) string {
|
---|
| 124 | return convertExt(path, extGCSS)
|
---|
| 125 | }
|
---|
| 126 |
|
---|
| 127 | // convertExt converts path's extension into ext.
|
---|
| 128 | func convertExt(path string, ext string) string {
|
---|
| 129 | return strings.TrimSuffix(path, filepath.Ext(path)) + ext
|
---|
| 130 | }
|
---|