forked from gotailwindcss/tailwind
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
apply.go
156 lines (120 loc) · 3.37 KB
/
apply.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package tailwind
import (
"bytes"
"errors"
"fmt"
"io"
"github.com/tdewolff/parse/v2"
"github.com/tdewolff/parse/v2/css"
)
type applier struct {
m map[string]string
}
func (a *applier) apply(names []string) ([]byte, error) {
ret := make([]byte, 0, len(names)*8)
for _, name := range names {
css, ok := a.m[name]
if !ok {
return ret, fmt.Errorf("unknown @apply name: %s", name)
}
ret = append(ret, css...)
}
return ret, nil
}
func newApplier(dist Dist) (*applier, error) {
var a applier
rc, err := dist.OpenDist("utilities")
if err != nil {
return nil, err
}
defer rc.Close()
a.m = make(map[string]string, 128)
depth := 0
entryName := ""
var entryData bytes.Buffer
_ = entryData
inp := parse.NewInput(rc)
p := css.NewParser(inp, false)
parseLoop:
for {
gt, tt, data := p.Next()
_ = tt
_ = data
switch gt {
case css.ErrorGrammar:
err := p.Err()
if errors.Is(err, io.EOF) {
break parseLoop
}
return nil, fmt.Errorf("applier.setupOnce: %w", err)
case css.AtRuleGrammar:
// ignored
case css.BeginAtRuleGrammar:
depth++
case css.EndAtRuleGrammar:
depth--
case css.BeginRulesetGrammar:
if depth != 0 { // ignore everything not at top level
continue parseLoop
}
// only handle rules exactly maching pattern [Delim(".") Ident("someclass")]
ts := trimTokenWs(p.Values())
if !(len(ts) == 2 &&
(ts[0].TokenType == css.DelimToken && bytes.Equal(ts[0].Data, []byte(`.`))) &&
(ts[1].TokenType == css.IdentToken && len(ts[1].Data) > 0)) {
continue parseLoop
}
name := string(ts[1].Data)
if entryName != "" { // this should not be possible, just make sure
panic(fmt.Errorf("about to start new entry %q but already in entry %q", name, entryName))
}
entryName = name
// Delim('.') Ident('space-y-0')
// log.Printf("applier BeginRulesetGrammar: data=%q, p.Values=%v", data, p.Values())
// log.Printf("BeginRulesetGrammar: classes=%v (values=%v)", toklistClasses(p.Values()), p.Values())
// inEntryName
// err := write(w, data, p.Values(), '{')
// if err != nil {
// return err
// }
case css.EndRulesetGrammar:
// we only need to look at entries that are closing
if entryName == "" {
continue parseLoop
}
b := entryData.Bytes()
b = bytes.TrimSpace(b)
a.m[entryName] = string(b)
entryData.Reset()
entryName = ""
case css.DeclarationGrammar:
if entryName == "" { // ignore content not inside an appropriate entry
continue parseLoop
}
err := write(&entryData, data, ':', p.Values(), ';')
if err != nil {
return nil, err
}
case css.CustomPropertyGrammar:
if entryName == "" { // ignore content not inside an appropriate entry
continue parseLoop
}
// panic(fmt.Errorf(`CustomPropertyGrammar unsupported: data=%q, p.Values=%v`, data, p.Values()))
err := write(&entryData, data, ':', p.Values(), ';')
if err != nil {
return nil, err
}
case css.QualifiedRuleGrammar:
// FIXME: still not sure about when this is used...
// panic(fmt.Errorf("applier: QualifiedRuleGrammar not yet implemented"))
continue // should be okay to skip for now...
case css.TokenGrammar:
continue // just skip
case css.CommentGrammar:
continue // strip comments
default: // verify we aren't missing a type
panic(fmt.Errorf("unexpected grammar type %v at offset %v", gt, inp.Offset()))
}
}
return &a, nil
}