236 lines
5.0 KiB
JavaScript
236 lines
5.0 KiB
JavaScript
"use strict"
|
|
|
|
// external tooling
|
|
const valueParser = require("postcss-value-parser")
|
|
|
|
// extended tooling
|
|
const { stringify } = valueParser
|
|
|
|
module.exports = function parseStatements(result, styles, conditions, from) {
|
|
const statements = []
|
|
let nodes = []
|
|
|
|
styles.each(node => {
|
|
let stmt
|
|
if (node.type === "atrule") {
|
|
if (node.name === "import")
|
|
stmt = parseImport(result, node, conditions, from)
|
|
else if (node.name === "charset")
|
|
stmt = parseCharset(result, node, conditions, from)
|
|
}
|
|
|
|
if (stmt) {
|
|
if (nodes.length) {
|
|
statements.push({
|
|
type: "nodes",
|
|
nodes,
|
|
conditions: [...conditions],
|
|
from,
|
|
})
|
|
nodes = []
|
|
}
|
|
statements.push(stmt)
|
|
} else nodes.push(node)
|
|
})
|
|
|
|
if (nodes.length) {
|
|
statements.push({
|
|
type: "nodes",
|
|
nodes,
|
|
conditions: [...conditions],
|
|
from,
|
|
})
|
|
}
|
|
|
|
return statements
|
|
}
|
|
|
|
function parseCharset(result, atRule, conditions, from) {
|
|
if (atRule.prev()) {
|
|
return result.warn("@charset must precede all other statements", {
|
|
node: atRule,
|
|
})
|
|
}
|
|
return {
|
|
type: "charset",
|
|
node: atRule,
|
|
conditions: [...conditions],
|
|
from,
|
|
}
|
|
}
|
|
|
|
function parseImport(result, atRule, conditions, from) {
|
|
let prev = atRule.prev()
|
|
|
|
// `@import` statements may follow other `@import` statements.
|
|
if (prev) {
|
|
do {
|
|
if (
|
|
prev.type === "comment" ||
|
|
(prev.type === "atrule" && prev.name === "import")
|
|
) {
|
|
prev = prev.prev()
|
|
continue
|
|
}
|
|
|
|
break
|
|
} while (prev)
|
|
}
|
|
|
|
// All `@import` statements may be preceded by `@charset` or `@layer` statements.
|
|
// But the `@import` statements must be consecutive.
|
|
if (prev) {
|
|
do {
|
|
if (
|
|
prev.type === "comment" ||
|
|
(prev.type === "atrule" &&
|
|
(prev.name === "charset" || (prev.name === "layer" && !prev.nodes)))
|
|
) {
|
|
prev = prev.prev()
|
|
continue
|
|
}
|
|
|
|
return result.warn(
|
|
"@import must precede all other statements (besides @charset or empty @layer)",
|
|
{ node: atRule },
|
|
)
|
|
} 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",
|
|
uri: "",
|
|
fullUri: "",
|
|
node: atRule,
|
|
conditions: [...conditions],
|
|
from,
|
|
}
|
|
|
|
let layer
|
|
let media
|
|
let supports
|
|
|
|
for (let i = 0; i < params.length; i++) {
|
|
const node = params[i]
|
|
|
|
if (node.type === "space" || node.type === "comment") continue
|
|
|
|
if (node.type === "string") {
|
|
if (stmt.uri) {
|
|
return result.warn(`Multiple url's in '${atRule.toString()}'`, {
|
|
node: atRule,
|
|
})
|
|
}
|
|
|
|
if (!node.value) {
|
|
return result.warn(`Unable to find uri in '${atRule.toString()}'`, {
|
|
node: atRule,
|
|
})
|
|
}
|
|
|
|
stmt.uri = node.value
|
|
stmt.fullUri = stringify(node)
|
|
continue
|
|
}
|
|
|
|
if (node.type === "function" && /^url$/i.test(node.value)) {
|
|
if (stmt.uri) {
|
|
return result.warn(`Multiple url's in '${atRule.toString()}'`, {
|
|
node: atRule,
|
|
})
|
|
}
|
|
|
|
if (!node.nodes?.[0]?.value) {
|
|
return result.warn(`Unable to find uri in '${atRule.toString()}'`, {
|
|
node: atRule,
|
|
})
|
|
}
|
|
|
|
stmt.uri = node.nodes[0].value
|
|
stmt.fullUri = stringify(node)
|
|
continue
|
|
}
|
|
|
|
if (!stmt.uri) {
|
|
return result.warn(`Unable to find uri in '${atRule.toString()}'`, {
|
|
node: atRule,
|
|
})
|
|
}
|
|
|
|
if (
|
|
(node.type === "word" || node.type === "function") &&
|
|
/^layer$/i.test(node.value)
|
|
) {
|
|
if (typeof layer !== "undefined") {
|
|
return result.warn(`Multiple layers in '${atRule.toString()}'`, {
|
|
node: atRule,
|
|
})
|
|
}
|
|
|
|
if (typeof supports !== "undefined") {
|
|
return result.warn(
|
|
`layers must be defined before support conditions in '${atRule.toString()}'`,
|
|
{
|
|
node: atRule,
|
|
},
|
|
)
|
|
}
|
|
|
|
if (node.nodes) {
|
|
layer = stringify(node.nodes)
|
|
} else {
|
|
layer = ""
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
if (node.type === "function" && /^supports$/i.test(node.value)) {
|
|
if (typeof supports !== "undefined") {
|
|
return result.warn(
|
|
`Multiple support conditions in '${atRule.toString()}'`,
|
|
{
|
|
node: atRule,
|
|
},
|
|
)
|
|
}
|
|
|
|
supports = stringify(node.nodes)
|
|
|
|
continue
|
|
}
|
|
|
|
media = stringify(params.slice(i))
|
|
break
|
|
}
|
|
|
|
if (!stmt.uri) {
|
|
return result.warn(`Unable to find uri in '${atRule.toString()}'`, {
|
|
node: atRule,
|
|
})
|
|
}
|
|
|
|
if (
|
|
typeof media !== "undefined" ||
|
|
typeof layer !== "undefined" ||
|
|
typeof supports !== "undefined"
|
|
) {
|
|
stmt.conditions.push({
|
|
layer,
|
|
media,
|
|
supports,
|
|
})
|
|
}
|
|
|
|
return stmt
|
|
}
|