66
|
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 }
|