1 | "use strict"
|
2 |
|
3 |
|
4 | const valueParser = require("postcss-value-parser")
|
5 |
|
6 |
|
7 | const { stringify } = valueParser
|
8 |
|
9 | module.exports = function parseStatements(result, styles, conditions, from) {
|
10 | const statements = []
|
11 | let nodes = []
|
12 |
|
13 | styles.each(node => {
|
14 | let stmt
|
15 | if (node.type === "atrule") {
|
16 | if (node.name === "import")
|
17 | stmt = parseImport(result, node, conditions, from)
|
18 | else if (node.name === "charset")
|
19 | stmt = parseCharset(result, node, conditions, from)
|
20 | }
|
21 |
|
22 | if (stmt) {
|
23 | if (nodes.length) {
|
24 | statements.push({
|
25 | type: "nodes",
|
26 | nodes,
|
27 | conditions: [...conditions],
|
28 | from,
|
29 | })
|
30 | nodes = []
|
31 | }
|
32 | statements.push(stmt)
|
33 | } else nodes.push(node)
|
34 | })
|
35 |
|
36 | if (nodes.length) {
|
37 | statements.push({
|
38 | type: "nodes",
|
39 | nodes,
|
40 | conditions: [...conditions],
|
41 | from,
|
42 | })
|
43 | }
|
44 |
|
45 | return statements
|
46 | }
|
47 |
|
48 | function parseCharset(result, atRule, conditions, from) {
|
49 | if (atRule.prev()) {
|
50 | return result.warn("@charset must precede all other statements", {
|
51 | node: atRule,
|
52 | })
|
53 | }
|
54 | return {
|
55 | type: "charset",
|
56 | node: atRule,
|
57 | conditions: [...conditions],
|
58 | from,
|
59 | }
|
60 | }
|
61 |
|
62 | function parseImport(result, atRule, conditions, from) {
|
63 | let prev = atRule.prev()
|
64 |
|
65 |
|
66 | if (prev) {
|
67 | do {
|
68 | if (
|
69 | prev.type === "comment" ||
|
70 | (prev.type === "atrule" && prev.name === "import")
|
71 | ) {
|
72 | prev = prev.prev()
|
73 | continue
|
74 | }
|
75 |
|
76 | break
|
77 | } while (prev)
|
78 | }
|
79 |
|
80 |
|
81 |
|
82 | if (prev) {
|
83 | do {
|
84 | if (
|
85 | prev.type === "comment" ||
|
86 | (prev.type === "atrule" &&
|
87 | (prev.name === "charset" || (prev.name === "layer" && !prev.nodes)))
|
88 | ) {
|
89 | prev = prev.prev()
|
90 | continue
|
91 | }
|
92 |
|
93 | return result.warn(
|
94 | "@import must precede all other statements (besides @charset or empty @layer)",
|
95 | { node: atRule },
|
96 | )
|
97 | } while (prev)
|
98 | }
|
99 |
|
100 | if (atRule.nodes) {
|
101 | return result.warn(
|
102 | "It looks like you didn't end your @import statement correctly. " +
|
103 | "Child nodes are attached to it.",
|
104 | { node: atRule },
|
105 | )
|
106 | }
|
107 |
|
108 | const params = valueParser(atRule.params).nodes
|
109 | const stmt = {
|
110 | type: "import",
|
111 | uri: "",
|
112 | fullUri: "",
|
113 | node: atRule,
|
114 | conditions: [...conditions],
|
115 | from,
|
116 | }
|
117 |
|
118 | let layer
|
119 | let media
|
120 | let supports
|
121 |
|
122 | for (let i = 0; i < params.length; i++) {
|
123 | const node = params[i]
|
124 |
|
125 | if (node.type === "space" || node.type === "comment") continue
|
126 |
|
127 | if (node.type === "string") {
|
128 | if (stmt.uri) {
|
129 | return result.warn(`Multiple url's in '${atRule.toString()}'`, {
|
130 | node: atRule,
|
131 | })
|
132 | }
|
133 |
|
134 | if (!node.value) {
|
135 | return result.warn(`Unable to find uri in '${atRule.toString()}'`, {
|
136 | node: atRule,
|
137 | })
|
138 | }
|
139 |
|
140 | stmt.uri = node.value
|
141 | stmt.fullUri = stringify(node)
|
142 | continue
|
143 | }
|
144 |
|
145 | if (node.type === "function" && /^url$/i.test(node.value)) {
|
146 | if (stmt.uri) {
|
147 | return result.warn(`Multiple url's in '${atRule.toString()}'`, {
|
148 | node: atRule,
|
149 | })
|
150 | }
|
151 |
|
152 | if (!node.nodes?.[0]?.value) {
|
153 | return result.warn(`Unable to find uri in '${atRule.toString()}'`, {
|
154 | node: atRule,
|
155 | })
|
156 | }
|
157 |
|
158 | stmt.uri = node.nodes[0].value
|
159 | stmt.fullUri = stringify(node)
|
160 | continue
|
161 | }
|
162 |
|
163 | if (!stmt.uri) {
|
164 | return result.warn(`Unable to find uri in '${atRule.toString()}'`, {
|
165 | node: atRule,
|
166 | })
|
167 | }
|
168 |
|
169 | if (
|
170 | (node.type === "word" || node.type === "function") &&
|
171 | /^layer$/i.test(node.value)
|
172 | ) {
|
173 | if (typeof layer !== "undefined") {
|
174 | return result.warn(`Multiple layers in '${atRule.toString()}'`, {
|
175 | node: atRule,
|
176 | })
|
177 | }
|
178 |
|
179 | if (typeof supports !== "undefined") {
|
180 | return result.warn(
|
181 | `layers must be defined before support conditions in '${atRule.toString()}'`,
|
182 | {
|
183 | node: atRule,
|
184 | },
|
185 | )
|
186 | }
|
187 |
|
188 | if (node.nodes) {
|
189 | layer = stringify(node.nodes)
|
190 | } else {
|
191 | layer = ""
|
192 | }
|
193 |
|
194 | continue
|
195 | }
|
196 |
|
197 | if (node.type === "function" && /^supports$/i.test(node.value)) {
|
198 | if (typeof supports !== "undefined") {
|
199 | return result.warn(
|
200 | `Multiple support conditions in '${atRule.toString()}'`,
|
201 | {
|
202 | node: atRule,
|
203 | },
|
204 | )
|
205 | }
|
206 |
|
207 | supports = stringify(node.nodes)
|
208 |
|
209 | continue
|
210 | }
|
211 |
|
212 | media = stringify(params.slice(i))
|
213 | break
|
214 | }
|
215 |
|
216 | if (!stmt.uri) {
|
217 | return result.warn(`Unable to find uri in '${atRule.toString()}'`, {
|
218 | node: atRule,
|
219 | })
|
220 | }
|
221 |
|
222 | if (
|
223 | typeof media !== "undefined" ||
|
224 | typeof layer !== "undefined" ||
|
225 | typeof supports !== "undefined"
|
226 | ) {
|
227 | stmt.conditions.push({
|
228 | layer,
|
229 | media,
|
230 | supports,
|
231 | })
|
232 | }
|
233 |
|
234 | return stmt
|
235 | }
|