[67] | 1 | package gcss
|
---|
| 2 |
|
---|
| 3 | import (
|
---|
| 4 | "bytes"
|
---|
| 5 | "fmt"
|
---|
| 6 | "io"
|
---|
| 7 | "strings"
|
---|
| 8 | )
|
---|
| 9 |
|
---|
| 10 | // declaration represents a declaration of CSS.
|
---|
| 11 | type declaration struct {
|
---|
| 12 | elementBase
|
---|
| 13 | property string
|
---|
| 14 | value string
|
---|
| 15 | }
|
---|
| 16 |
|
---|
| 17 | // WriteTo writes the declaration to the writer.
|
---|
| 18 | func (dec *declaration) WriteTo(w io.Writer) (int64, error) {
|
---|
| 19 | return dec.writeTo(w, nil)
|
---|
| 20 | }
|
---|
| 21 |
|
---|
| 22 | // writeTo writes the declaration to the writer.
|
---|
| 23 | func (dec *declaration) writeTo(w io.Writer, params map[string]string) (int64, error) {
|
---|
| 24 | bf := new(bytes.Buffer)
|
---|
| 25 |
|
---|
| 26 | bf.WriteString(dec.property)
|
---|
| 27 | bf.WriteString(colon)
|
---|
| 28 |
|
---|
| 29 | for i, v := range strings.Split(dec.value, space) {
|
---|
| 30 | if i > 0 {
|
---|
| 31 | bf.WriteString(space)
|
---|
| 32 | }
|
---|
| 33 |
|
---|
| 34 | for j, w := range strings.Split(v, comma) {
|
---|
| 35 | if j > 0 {
|
---|
| 36 | bf.WriteString(comma)
|
---|
| 37 | }
|
---|
| 38 |
|
---|
| 39 | if strings.HasPrefix(w, dollarMark) {
|
---|
| 40 | // Writing to the bytes.Buffer never returns an error.
|
---|
| 41 | dec.writeParamTo(bf, strings.TrimPrefix(w, dollarMark), params)
|
---|
| 42 | } else {
|
---|
| 43 | bf.WriteString(w)
|
---|
| 44 | }
|
---|
| 45 | }
|
---|
| 46 | }
|
---|
| 47 |
|
---|
| 48 | bf.WriteString(semicolon)
|
---|
| 49 |
|
---|
| 50 | n, err := w.Write(bf.Bytes())
|
---|
| 51 |
|
---|
| 52 | return int64(n), err
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | // writeParam writes the param to the writer.
|
---|
| 56 | func (dec *declaration) writeParamTo(w io.Writer, name string, params map[string]string) (int64, error) {
|
---|
| 57 | if s, ok := params[name]; ok {
|
---|
| 58 | if strings.HasPrefix(s, dollarMark) {
|
---|
| 59 | if v, ok := dec.Context().vars[strings.TrimPrefix(s, dollarMark)]; ok {
|
---|
| 60 | return v.WriteTo(w)
|
---|
| 61 | }
|
---|
| 62 | return 0, nil
|
---|
| 63 | }
|
---|
| 64 |
|
---|
| 65 | n, err := w.Write([]byte(s))
|
---|
| 66 | return int64(n), err
|
---|
| 67 | }
|
---|
| 68 |
|
---|
| 69 | if v, ok := dec.Context().vars[name]; ok {
|
---|
| 70 | return v.WriteTo(w)
|
---|
| 71 | }
|
---|
| 72 |
|
---|
| 73 | return 0, nil
|
---|
| 74 | }
|
---|
| 75 |
|
---|
| 76 | // declarationPV extracts a declaration property and value
|
---|
| 77 | // from the line.
|
---|
| 78 | func declarationPV(ln *line) (string, string, error) {
|
---|
| 79 | pv := strings.SplitN(strings.TrimSpace(ln.s), space, 2)
|
---|
| 80 |
|
---|
| 81 | if len(pv) < 2 {
|
---|
| 82 | return "", "", fmt.Errorf("declaration's property and value should be divided by a space [line: %d]", ln.no)
|
---|
| 83 | }
|
---|
| 84 |
|
---|
| 85 | if !strings.HasSuffix(pv[0], colon) {
|
---|
| 86 | return "", "", fmt.Errorf("property should end with a colon [line: %d]", ln.no)
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | return strings.TrimSuffix(pv[0], colon), pv[1], nil
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | // newDeclaration creates and returns a declaration.
|
---|
| 93 | func newDeclaration(ln *line, parent element) (*declaration, error) {
|
---|
| 94 | property, value, err := declarationPV(ln)
|
---|
| 95 |
|
---|
| 96 | if err != nil {
|
---|
| 97 | return nil, err
|
---|
| 98 | }
|
---|
| 99 |
|
---|
| 100 | if strings.HasSuffix(value, semicolon) {
|
---|
| 101 | return nil, fmt.Errorf("declaration must not end with %q [line: %d]", semicolon, ln.no)
|
---|
| 102 | }
|
---|
| 103 |
|
---|
| 104 | return &declaration{
|
---|
| 105 | elementBase: newElementBase(ln, parent),
|
---|
| 106 | property: property,
|
---|
| 107 | value: value,
|
---|
| 108 | }, nil
|
---|
| 109 | }
|
---|