173 lines
3.7 KiB
JavaScript
173 lines
3.7 KiB
JavaScript
|
"use strict"
|
||
|
|
||
|
// external tooling
|
||
|
const valueParser = require("postcss-value-parser")
|
||
|
|
||
|
// extended tooling
|
||
|
const { stringify } = valueParser
|
||
|
|
||
|
function split(params, start) {
|
||
|
const list = []
|
||
|
const last = params.reduce((item, node, index) => {
|
||
|
if (index < start) return ""
|
||
|
if (node.type === "div" && node.value === ",") {
|
||
|
list.push(item)
|
||
|
return ""
|
||
|
}
|
||
|
return item + stringify(node)
|
||
|
}, "")
|
||
|
list.push(last)
|
||
|
return list
|
||
|
}
|
||
|
|
||
|
module.exports = function (result, styles) {
|
||
|
const statements = []
|
||
|
let nodes = []
|
||
|
|
||
|
styles.each(node => {
|
||
|
let stmt
|
||
|
if (node.type === "atrule") {
|
||
|
if (node.name === "import") stmt = parseImport(result, node)
|
||
|
else if (node.name === "media") stmt = parseMedia(result, node)
|
||
|
else if (node.name === "charset") stmt = parseCharset(result, node)
|
||
|
}
|
||
|
|
||
|
if (stmt) {
|
||
|
if (nodes.length) {
|
||
|
statements.push({
|
||
|
type: "nodes",
|
||
|
nodes,
|
||
|
media: [],
|
||
|
layer: [],
|
||
|
})
|
||
|
nodes = []
|
||
|
}
|
||
|
statements.push(stmt)
|
||
|
} else nodes.push(node)
|
||
|
})
|
||
|
|
||
|
if (nodes.length) {
|
||
|
statements.push({
|
||
|
type: "nodes",
|
||
|
nodes,
|
||
|
media: [],
|
||
|
layer: [],
|
||
|
})
|
||
|
}
|
||
|
|
||
|
return statements
|
||
|
}
|
||
|
|
||
|
function parseMedia(result, atRule) {
|
||
|
const params = valueParser(atRule.params).nodes
|
||
|
return {
|
||
|
type: "media",
|
||
|
node: atRule,
|
||
|
media: split(params, 0),
|
||
|
layer: [],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function parseCharset(result, atRule) {
|
||
|
if (atRule.prev()) {
|
||
|
return result.warn("@charset must precede all other statements", {
|
||
|
node: atRule,
|
||
|
})
|
||
|
}
|
||
|
return {
|
||
|
type: "charset",
|
||
|
node: atRule,
|
||
|
media: [],
|
||
|
layer: [],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function parseImport(result, atRule) {
|
||
|
let prev = atRule.prev()
|
||
|
if (prev) {
|
||
|
do {
|
||
|
if (
|
||
|
prev.type !== "comment" &&
|
||
|
(prev.type !== "atrule" ||
|
||
|
(prev.name !== "import" &&
|
||
|
prev.name !== "charset" &&
|
||
|
!(prev.name === "layer" && !prev.nodes)))
|
||
|
) {
|
||
|
return result.warn(
|
||
|
"@import must precede all other statements (besides @charset or empty @layer)",
|
||
|
{ node: atRule }
|
||
|
)
|
||
|
}
|
||
|
prev = prev.prev()
|
||
|
} while (prev)
|
||
|
}
|
||
|
|
||
|
if (atRule.nodes) {
|
||
|
return result.warn(
|
||
|
"It looks like you didn't end your @import statement correctly. " +
|
||
|
"Child nodes are attached to it.",
|
||
|
{ node: atRule }
|
||
|
)
|
||
|
}
|
||
|
|
||
|
const params = valueParser(atRule.params).nodes
|
||
|
const stmt = {
|
||
|
type: "import",
|
||
|
node: atRule,
|
||
|
media: [],
|
||
|
layer: [],
|
||
|
}
|
||
|
|
||
|
// prettier-ignore
|
||
|
if (
|
||
|
!params.length ||
|
||
|
(
|
||
|
params[0].type !== "string" ||
|
||
|
!params[0].value
|
||
|
) &&
|
||
|
(
|
||
|
params[0].type !== "function" ||
|
||
|
params[0].value !== "url" ||
|
||
|
!params[0].nodes.length ||
|
||
|
!params[0].nodes[0].value
|
||
|
)
|
||
|
) {
|
||
|
return result.warn(`Unable to find uri in '${ atRule.toString() }'`, {
|
||
|
node: atRule,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
if (params[0].type === "string") stmt.uri = params[0].value
|
||
|
else stmt.uri = params[0].nodes[0].value
|
||
|
stmt.fullUri = stringify(params[0])
|
||
|
|
||
|
let remainder = params
|
||
|
if (remainder.length > 2) {
|
||
|
if (
|
||
|
(remainder[2].type === "word" || remainder[2].type === "function") &&
|
||
|
remainder[2].value === "layer"
|
||
|
) {
|
||
|
if (remainder[1].type !== "space") {
|
||
|
return result.warn("Invalid import layer statement", { node: atRule })
|
||
|
}
|
||
|
|
||
|
if (remainder[2].nodes) {
|
||
|
stmt.layer = [stringify(remainder[2].nodes)]
|
||
|
} else {
|
||
|
stmt.layer = [""]
|
||
|
}
|
||
|
remainder = remainder.slice(2)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (remainder.length > 2) {
|
||
|
if (remainder[1].type !== "space") {
|
||
|
return result.warn("Invalid import media statement", { node: atRule })
|
||
|
}
|
||
|
|
||
|
stmt.media = split(remainder, 2)
|
||
|
}
|
||
|
|
||
|
return stmt
|
||
|
}
|