UNPKG

2.91 kBJavaScriptView Raw
1"use strict"
2
3// external tooling
4const valueParser = require("postcss-value-parser")
5
6// extended tooling
7const stringify = valueParser.stringify
8
9function split(params, start) {
10 const list = []
11 const last = params.reduce((item, node, index) => {
12 if (index < start) return ""
13 if (node.type === "div" && node.value === ",") {
14 list.push(item)
15 return ""
16 }
17 return item + stringify(node)
18 }, "")
19 list.push(last)
20 return list
21}
22
23module.exports = function (result, styles) {
24 const statements = []
25 let nodes = []
26
27 styles.each(node => {
28 let stmt
29 if (node.type === "atrule") {
30 if (node.name === "import") stmt = parseImport(result, node)
31 else if (node.name === "media") stmt = parseMedia(result, node)
32 }
33
34 if (stmt) {
35 if (nodes.length) {
36 statements.push({
37 type: "nodes",
38 nodes: nodes,
39 media: [],
40 })
41 nodes = []
42 }
43 statements.push(stmt)
44 } else nodes.push(node)
45 })
46
47 if (nodes.length) {
48 statements.push({
49 type: "nodes",
50 nodes: nodes,
51 media: [],
52 })
53 }
54
55 return statements
56}
57
58function parseMedia(result, atRule) {
59 const params = valueParser(atRule.params).nodes
60 return {
61 type: "media",
62 node: atRule,
63 media: split(params, 0),
64 }
65}
66
67function parseImport(result, atRule) {
68 let prev = getPrev(atRule)
69 if (prev) {
70 do {
71 if (
72 prev.type !== "atrule" ||
73 (prev.name !== "import" && prev.name !== "charset")
74 ) {
75 return result.warn(
76 "@import must precede all other statements (besides @charset)",
77 { node: atRule }
78 )
79 } else prev = getPrev(prev)
80 } while (prev)
81 }
82
83 if (atRule.nodes) {
84 return result.warn(
85 "It looks like you didn't end your @import statement correctly. " +
86 "Child nodes are attached to it.",
87 { node: atRule }
88 )
89 }
90
91 const params = valueParser(atRule.params).nodes
92 const stmt = {
93 type: "import",
94 node: atRule,
95 media: [],
96 }
97
98 // prettier-ignore
99 if (
100 !params.length ||
101 (
102 params[0].type !== "string" ||
103 !params[0].value
104 ) &&
105 (
106 params[0].type !== "function" ||
107 params[0].value !== "url" ||
108 !params[0].nodes.length ||
109 !params[0].nodes[0].value
110 )
111 ) {
112 return result.warn(`Unable to find uri in '${ atRule.toString() }'`, {
113 node: atRule,
114 })
115 }
116
117 if (params[0].type === "string") stmt.uri = params[0].value
118 else stmt.uri = params[0].nodes[0].value
119 stmt.fullUri = stringify(params[0])
120
121 if (params.length > 2) {
122 if (params[1].type !== "space") {
123 return result.warn("Invalid import media statement", { node: atRule })
124 }
125 stmt.media = split(params, 2)
126 }
127
128 return stmt
129}
130
131function getPrev(item) {
132 let prev = item.prev()
133 while (prev && prev.type === "comment") {
134 prev = prev.prev()
135 }
136 return prev
137}